summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/ipc/ipcd
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
commit16f504a9dca3fe3b70568f67b7d41241ae485288 (patch)
treec60f36ada0496ba928b7161059ba5ab1ab224f9d /src/libs/xpcom18a4/ipc/ipcd
parentInitial commit. (diff)
downloadvirtualbox-upstream.tar.xz
virtualbox-upstream.zip
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libs/xpcom18a4/ipc/ipcd')
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/Makefile.in64
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/Makefile.kup0
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/Makefile.kup0
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/public/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/public/Makefile.in59
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.h53
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIClientObserver.idl51
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIMessageObserver.idl64
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIService.idl228
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/public/ipcdclient.h326
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in101
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.kup0
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnection.h147
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionStub.cpp70
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp615
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionWin.cpp332
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/ipcModuleFactory.cpp196
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.cpp120
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.h51
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp1505
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in52
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h240
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h151
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore2
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in88
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp235
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h144
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp316
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h48
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp245
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h70
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp235
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h82
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h65
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp77
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp600
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp408
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in49
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.kup0
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.in52
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.kup0
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/Makefile.in53
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl79
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.in66
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.kup0
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp4210
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h365
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/Makefile.in33
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestClient.js106
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestDConnect.cpp268
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestServer.js66
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in52
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/Makefile.in58
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcILockService.idl65
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcLockCID.h53
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/Makefile.in69
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp87
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h98
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.cpp168
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.h63
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/Makefile.in92
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp337
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/Makefile.in67
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp244
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/Makefile.in52
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/.cvsignore9
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/Makefile.in75
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmCID.h53
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmModule.cpp71
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/.cvsignore5
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/Makefile.in61
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp107
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.h234
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmUtils.h93
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.cpp179
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.h160
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/.cvsignore11
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/Makefile.in100
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.cpp137
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.h109
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.cpp223
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.h186
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.cpp162
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.h147
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/Makefile.in53
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl100
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl239
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/.cvsignore4
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/Makefile.in64
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp504
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h196
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/.cvsignore6
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/Makefile.in68
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/tmModuleTest.cpp323
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/ipc.pkg21
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in65
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp104
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h98
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp62
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h108
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h211
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp181
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.h111
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp280
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h214
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp81
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.h206
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h46
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageUtils.h66
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.cpp80
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h114
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp303
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h502
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore2
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in69
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp338
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/test/module/Makefile.in81
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/test/module/TestModule.cpp62
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in49
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/public/Makefile.in53
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageReader.h89
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageWriter.h99
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore1
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in56
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageReader.cpp100
-rw-r--r--src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageWriter.cpp130
140 files changed, 21568 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/ipc/ipcd/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/Makefile.in
new file mode 100644
index 00000000..d5f24007
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/Makefile.in
@@ -0,0 +1,64 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+
+PACKAGE_FILE = ipc.pkg
+
+DIRS = \
+ util \
+ shared/src \
+ daemon/public \
+ client/public \
+ extensions \
+ client/src \
+ daemon/src \
+ $(NULL)
+
+ifdef ENABLE_TESTS
+DIRS += test
+endif
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/Makefile.kup
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/client/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/Makefile.kup
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/client/public/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/client/public/Makefile.in
new file mode 100644
index 00000000..896e68b8
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/Makefile.in
@@ -0,0 +1,59 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+
+EXPORTS = \
+ ipcdclient.h \
+ ipcCID.h \
+ $(NULL)
+
+XPIDLSRCS = \
+ ipcIService.idl \
+ ipcIMessageObserver.idl \
+ ipcIClientObserver.idl \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.h b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.h
new file mode 100644
index 00000000..4863ff0d
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.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 <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef 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} \
+}
+
+#endif // !ipcCID_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIClientObserver.idl b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIClientObserver.idl
new file mode 100644
index 00000000..c72d0909
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIClientObserver.idl
@@ -0,0 +1,51 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * ipcIClientObserver
+ */
+[scriptable, uuid(42283079-030c-4b13-b069-a08b7ad5eab2)]
+interface ipcIClientObserver : nsISupports
+{
+ const unsigned long CLIENT_UP = 1;
+ const unsigned long CLIENT_DOWN = 2;
+
+ void onClientStateChange(in unsigned long aClientID,
+ in unsigned long aClientState);
+};
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIMessageObserver.idl b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIMessageObserver.idl
new file mode 100644
index 00000000..db24b1f2
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIMessageObserver.idl
@@ -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 <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * ipcIMessageObserver
+ */
+[scriptable, uuid(e40a4a3c-2dc1-470e-ab7f-5675fe1f1384)]
+interface ipcIMessageObserver : nsISupports
+{
+ /**
+ * @param aSenderID
+ * the client id of the sender of this message. if sent by the
+ * daemon (or a deamon module), then this will have a value of 0.
+ * @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.
+ */
+ void onMessageAvailable(in unsigned long aSenderID,
+ in nsIDRef aTarget,
+ [array, const, size_is(aDataLen)]
+ in octet aData,
+ in unsigned long aDataLen);
+};
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIService.idl b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIService.idl
new file mode 100644
index 00000000..671b557d
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIService.idl
@@ -0,0 +1,228 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface ipcIMessageObserver;
+interface ipcIClientObserver;
+
+/**
+ * ipcIService
+ *
+ * the IPC service provides the means to communicate with an external IPC
+ * daemon and/or other mozilla-based applications on the same physical system.
+ * 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. the IPC daemon will be automatically
+ * started if necessary. when a connection has been established, the IPC
+ * service will enumerate the "ipc-startup-category" and broadcast an
+ * "ipc-startup" notification using the observer service.
+ *
+ * when the connection to the IPC daemon is closed, 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. the 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
+{
+ /**************************************************************************
+ * properties of this process
+ */
+
+ /**
+ * returns the "client ID" assigned to this process by the IPC daemon.
+ *
+ * @throws NS_ERROR_NOT_AVAILABLE if no connection to the IPC daemon.
+ */
+ readonly attribute unsigned long ID;
+
+ /**
+ * this process can appear under several client names. use the following
+ * methods to add or remove names for this process.
+ *
+ * for example, the mozilla browser might have the primary name "mozilla",
+ * but it could also register itself under the names "browser", "mail",
+ * "news", "addrbook", etc. other IPC clients can then query the IPC
+ * daemon for the client named "mail" in order to talk with a mail program.
+ *
+ * XXX An IPC client name resembles a XPCOM contract ID.
+ */
+ void addName(in string aName);
+ void removeName(in string aName);
+
+ /**
+ * add a new observer of client status change notifications.
+ */
+ void addClientObserver(in ipcIClientObserver aObserver);
+
+ /**
+ * remove an observer of client status change notifications.
+ */
+ void removeClientObserver(in ipcIClientObserver aObserver);
+
+ /**************************************************************************
+ * client query methods
+ */
+
+ /**
+ * resolve the given client name to the id of a connected client. this
+ * involves a round trip to the daemon, and as a result the calling thread
+ * may block on this function call while waiting for the daemon to respond.
+ */
+ unsigned long resolveClientName(in string aName);
+
+
+ /**
+ * tests whether a particular client is connected to the IPC daemon.
+ */
+ boolean clientExists(in unsigned long aClientID);
+
+
+ // XXX need other functions to enumerate clients, clients implementing targets, etc.
+ // enumerator getClients();
+ // enumerator getClientsSupportingTarget(in nsIDRef aTarget);
+ // enumerator getClientNames(in unsigned long aClientID);
+ // enumerator getClientTargets(in unsigned long aClientID);
+
+
+ /**************************************************************************
+ * message methods
+ */
+
+ /**
+ * 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.
+ * @param aOnCurrentThread
+ * if true, then the message observer will be called on the same
+ * thread that calls defineTarget. otherwise, aObserver will be
+ * called on a background thread.
+ */
+ void defineTarget(in nsIDRef aTarget,
+ in ipcIMessageObserver aObserver,
+ in boolean aOnCurrentThread);
+
+ /**
+ * send message asynchronously to a client or a module in the IPC daemon.
+ * there is no guarantee that the message will be delivered.
+ *
+ * @param aClientID
+ * the client ID of the foreign application that should receive this
+ * message. pass 0 to send a message to a module in the IPC daemon.
+ * @param aTarget
+ * the target of the message. if aClientID is 0, then this is the
+ * ID of the daemon module that should receive this message.
+ * @param aData
+ * the message data.
+ * @param aDataLen
+ * the message length.
+ */
+ void sendMessage(in unsigned long aReceiverID,
+ in nsIDRef aTarget,
+ [array, const, size_is(aDataLen)]
+ in octet aData,
+ in unsigned long aDataLen);
+
+ /**
+ * block the calling thread until a matching message is received.
+ *
+ * @param aSenderID
+ * pass 0 to wait for a message from the daemon. pass PR_UINT32_MAX
+ * to wait for a message from any source. otherwise, pass a client
+ * id to wait for a message from that particular client.
+ * @param aTarget
+ * wait for a message to be delivered to this target.
+ * @param aObserver
+ * this observer's OnMessageAvailable method is called when a
+ * matching message is available. pass null to use the default
+ * observer associated with aTarget.
+ * @param aTimeout
+ * indicates maximum length of time in milliseconds that this
+ * function may block the calling thread.
+ *
+ * @throws IPC_ERROR_WOULD_BLOCK if the timeout expires.
+ *
+ * the observer's OnMessageAvailable method may throw IPC_WAIT_NEXT_MESSAGE
+ * to indicate that it does not wish to handle the message that it was
+ * given, and that it will wait to be called with the next message. this
+ * enables the observer to keep messages in the queue that do not match the
+ * desired message. messages that remain in the queue will be dispatched
+ * asynchronously to the default message handler after waitMessage finishes.
+ *
+ * NOTE: this function may hang the calling thread until a matching message
+ * is received, so use it with caution.
+ */
+ void waitMessage(in unsigned long aSenderID,
+ in nsIDRef aTarget,
+ in ipcIMessageObserver aObserver,
+ in unsigned long aTimeout);
+
+ /**
+ * Call this method to disable the default message observer for a target.
+ */
+ void disableMessageObserver(in nsIDRef aTarget);
+
+ /**
+ * Call this method to re-enable the default message observer for a target.
+ */
+ void enableMessageObserver(in nsIDRef aTarget);
+};
+
+%{C++
+// category and observer event defines (XXX not yet implemented)
+#define IPC_SERVICE_STARTUP_CATEGORY "ipc-startup-category"
+#define IPC_SERVICE_STARTUP_TOPIC "ipc-startup"
+#define IPC_SERVICE_SHUTDOWN_TOPIC "ipc-shutdown"
+%}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcdclient.h b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcdclient.h
new file mode 100644
index 00000000..5cbed879
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcdclient.h
@@ -0,0 +1,326 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcdclient_h__
+#define ipcdclient_h__
+
+/*****************************************************************************
+ * This file provides a client-side API to the IPC daemon.
+ *
+ * This API can be used to communicate with other clients of the IPC daemon
+ * as well as modules running inside the IPC daemon.
+ *
+ * This API is meant to be used only on the application's main thread. It is
+ * assumed that callbacks can be dispatched via the main thread's event queue.
+ */
+
+#include "nscore.h"
+#include "nsID.h"
+#include "nsError.h"
+#include "ipcIMessageObserver.h"
+#include "ipcIClientObserver.h"
+
+/* This API is only provided for the extensions compiled into the IPCDC
+ * library, hence this API is hidden in the final DSO. */
+#define IPC_METHOD NS_HIDDEN_(nsresult)
+
+/* This value can be used to represent the client id of any client connected
+ * to the IPC daemon. */
+#define IPC_SENDER_ANY PR_UINT32_MAX
+
+/* This error code can only be returned by OnMessageAvailable, when called by
+ * IPC_WaitMessage. See IPC_WaitMessage for a description of how this error
+ * code may be used. */
+#define IPC_WAIT_NEXT_MESSAGE \
+ NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 10)
+
+#ifdef VBOX
+/* This error code can only be returned by the selector functions called by
+ * WaitTarget. The message should be dropped without processing. */
+#define IPC_DISCARD_MESSAGE \
+ NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 12)
+#endif /* VBOX */
+
+/* This error code is returned by IPC_WaitMessage under certain conditions. */
+#define IPC_ERROR_WOULD_BLOCK NS_BASE_STREAM_WOULD_BLOCK
+
+/*****************************************************************************
+ * Initialization and Shutdown
+ */
+
+// XXX limit these to the main thread, and call them from our module's ctor/dtor?
+
+/**
+ * Connects this process to the IPC daemon and initializes it for use as a
+ * client of the IPC daemon. This function must be called once before any
+ * other methods defined in this file can be used.
+ *
+ * @returns NS_ERROR_ALREADY_INITIALIZED if IPC_Shutdown was not called since
+ * the last time IPC_Init was called.
+ */
+IPC_METHOD IPC_Init();
+
+/**
+ * Disconnects this process from the IPC daemon. After this function is
+ * called, no other methods in this file except for IPC_Init may be called.
+ *
+ * This function calls all client observers (registered with
+ * IPC_AddClientObserver) before it actually disconnects from the IPC daemon,
+ * with aClientID parameter of the OnClientStateChange callback specially
+ * set to IPC_SENDER_ANY and aClientState set to CLIENT_DOWN. This gives
+ * the interested party an opportunity to perform a proper shutdown procedure.
+ * All IPC methods are still available inside OnClientStateChange call except
+ * the IPC_WaitMessage function, that will immediately fail with an error.
+ * OnClientStateChange is called on the same thread where this function is
+ * called.
+ *
+ * @returns NS_ERROR_NOT_INITIALIZED if IPC_Init has not been called or if
+ * IPC_Init did not return a success code.
+ */
+IPC_METHOD IPC_Shutdown();
+
+
+/*****************************************************************************
+ * The core messaging API
+ */
+
+/**
+ * Call this method to define a message target. A message target is defined
+ * by a UUID and a message observer. This observer is notified asynchronously
+ * whenever a message is sent to this target in this process.
+ *
+ * This function has three main effects:
+ * o If the message target is already defined, then this function simply
+ * resets its message observer.
+ * o If the message target is not already defined, then the message target
+ * is defined and the IPC daemon is notified of the existance of this
+ * message target.
+ * o If null is passed for the message observer, then the message target is
+ * removed, and the daemon is notified of the removal of this message target.
+ *
+ * If aOnCurrentThread is true, then notifications to the observer will occur
+ * on the current thread. This means that there must be a nsIEventTarget
+ * associated with the calling thread. If aOnCurrentThread is false, then
+ * notifications to the observer will occur on a background thread. In which
+ * case, the observer must be threadsafe.
+ */
+IPC_METHOD IPC_DefineTarget(
+ const nsID &aTarget,
+ ipcIMessageObserver *aObserver,
+ PRBool aOnCurrentThread = PR_TRUE
+);
+
+/**
+ * Call this method to temporarily disable the message observer configured
+ * for a message target.
+ */
+IPC_METHOD IPC_DisableMessageObserver(
+ const nsID &aTarget
+);
+
+/**
+ * Call this method to re-enable the message observer configured for a
+ * message target.
+ */
+IPC_METHOD IPC_EnableMessageObserver(
+ const nsID &aTarget
+);
+
+/**
+ * This function sends a message to the IPC daemon asynchronously. If
+ * aReceiverID is non-zero, then the message is forwarded to the client
+ * corresponding to that identifier.
+ *
+ * If there is no client corresponding to aRecieverID, then the IPC daemon will
+ * simply drop the message.
+ */
+IPC_METHOD IPC_SendMessage(
+ PRUint32 aReceiverID,
+ const nsID &aTarget,
+ const PRUint8 *aData,
+ PRUint32 aDataLen
+);
+
+/**
+ * This function blocks the calling thread until a message for the given target
+ * is received (optionally from the specified client).
+ *
+ * The aSenderID parameter is interpreted as follows:
+ * o If aSenderID is 0, then this function waits for a message to be sent by
+ * the IPC daemon.
+ * o If aSenderID is IPC_SENDER_ANY, then this function waits for a message
+ * to be sent from any source.
+ * o Otherwise, this function waits for a message to be sent by the client
+ * with ID given by aSenderID. If aSenderID does not identify a valid
+ * client, or if the client dies while waiting, then this function will
+ * return an error.
+ *
+ * The aObserver parameter is interpreted as follows:
+ * o If aObserver is null, then the default message observer for the target
+ * is invoked when the next message is received.
+ * o Otherwise, aObserver will be inovked when the next message is received.
+ *
+ * The aConsumer parameter is interpreted as follows:
+ * o If aObserver is null or aConsumer is null, this parameter is ignored.
+ * o Otherwise, aConsumer will be invoked right after (and only if) aObserver
+ * has accepted some message. It will receive exactly the same message
+ * that was accepted by aObserver.
+ *
+ * The aTimeout parameter is interpreted as follows:
+ * o If aTimeout is PR_INTERVAL_NO_TIMEOUT, then this function will block
+ * until a matching message is received.
+ * o If aTimeout is PR_INTERVAL_NO_WAIT, then this function will only inspect
+ * the current queue of messages. If no matching message is found, then
+ * IPC_ERROR_WOULD_BLOCK is returned.
+ * o Otherwise, aTimeout specifies the maximum amount of time to wait for a
+ * matching message to be received. If no matching message is found after
+ * the timeout expires, then IPC_ERROR_WOULD_BLOCK is returned.
+ *
+ * If aObserver's OnMessageAvailable function returns IPC_WAIT_NEXT_MESSAGE,
+ * then the function will continue blocking until the next matching message
+ * is received. Bypassed messages will be dispatched to the default message
+ * observer when the event queue, associated with the thread that called
+ * IPC_DefineTarget, is processed.
+ *
+ * There is a special case if aSenderID is IPC_SENDER_ANY and one of IPC clients
+ * dies while this function waits for a message. In this case, aObserver's
+ * OnMessageAvailable function is called with a special set of arguments:
+ * dead client id, empty target id and null message (both data and data length
+ * are zeroes). If it returns IPC_WAIT_NEXT_MESSAGE, IPC_WaitMessage continues
+ * blocking as usual, otherwise an error is immediately returned to the caller.
+ *
+ * aObserver is not expected to use any IPC system functons from within its
+ * OnMessageAvailable implementation. This is because the IPC system is not
+ * re-entrant during invocation of OnMessageAvailable function, and making other
+ * IPC calls can lead to unexpected results (like message losses or traps). On
+ * the contrary, aConsumer's OnMessageAvailable function is allowed to use the
+ * IPC system without any limitations.
+ *
+ * This function runs the risk of hanging the calling thread indefinitely if
+ * no matching message is ever received.
+ */
+IPC_METHOD IPC_WaitMessage(
+ PRUint32 aSenderID,
+ const nsID &aTarget,
+ ipcIMessageObserver *aObserver = nsnull,
+ ipcIMessageObserver *aConsumer = nsnull,
+ PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT
+);
+
+/*****************************************************************************/
+
+/**
+ * Returns the "ClientID" of the current process.
+ */
+IPC_METHOD IPC_GetID(
+ PRUint32 *aClientID
+);
+
+/**
+ * Adds a new name for the current process. The IPC daemon is notified of this
+ * change, which allows other processes to discover this process by the given
+ * name.
+ */
+IPC_METHOD IPC_AddName(
+ const char *aName
+);
+
+/**
+ * Removes a name associated with the current process.
+ */
+IPC_METHOD IPC_RemoveName(
+ const char *aName
+);
+
+/**
+ * Adds client observer. Will be called on the main thread.
+ */
+IPC_METHOD IPC_AddClientObserver(
+ ipcIClientObserver *aObserver
+);
+
+/**
+ * Removes client observer.
+ */
+IPC_METHOD IPC_RemoveClientObserver(
+ ipcIClientObserver *aObserver
+);
+
+/**
+ * Resolves the given client name to a client ID of a process connected to
+ * the IPC daemon.
+ */
+IPC_METHOD IPC_ResolveClientName(
+ const char *aName,
+ PRUint32 *aClientID
+);
+
+/**
+ * Tests whether the client is connected to the IPC daemon.
+ */
+IPC_METHOD IPC_ClientExists(
+ PRUint32 aClientID,
+ PRBool *aResult
+);
+
+/*****************************************************************************/
+
+/**
+ * This class can be used to temporarily disable the default message observer
+ * defined for a particular message target.
+ */
+class ipcDisableMessageObserverForScope
+{
+public:
+ ipcDisableMessageObserverForScope(const nsID &aTarget)
+ : mTarget(aTarget)
+ {
+ IPC_DisableMessageObserver(mTarget);
+ }
+
+ ~ipcDisableMessageObserverForScope()
+ {
+ IPC_EnableMessageObserver(mTarget);
+ }
+
+private:
+ const nsID &mTarget;
+};
+
+#define IPC_DISABLE_MESSAGE_OBSERVER_FOR_SCOPE(_t) \
+ ipcDisableMessageObserverForScope ipc_dmo_for_scope##_t(_t)
+
+#endif /* ipcdclient_h__ */
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in
new file mode 100644
index 00000000..b2854e35
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in
@@ -0,0 +1,101 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+LIBRARY_NAME = ipcdc
+EXPORT_LIBRARY = 1
+IS_COMPONENT = 1
+MODULE_NAME = ipcdclient
+
+REQUIRES = \
+ xpcom \
+ string \
+ $(NULL)
+
+CPPSRCS = \
+ ipcdclient.cpp \
+ ipcService.cpp \
+ ipcModuleFactory.cpp \
+ $(NULL)
+
+ifeq ($(OS_ARCH),WINNT)
+CPPSRCS += ipcConnectionWin.cpp
+else
+ifeq ($(OS_ARCH),BeOS)
+CPPSRCS += ipcConnectionStub.cpp
+else
+CPPSRCS += ipcConnectionUnix.cpp
+endif
+endif
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/../../shared/src \
+ -I$(srcdir)/../../extensions/lock/src \
+ -I$(srcdir)/../../extensions/transmngr/src \
+ -I$(srcdir)/../../extensions/transmngr/common \
+ $(NULL)
+
+SHARED_LIBRARY_LIBS = \
+ $(DIST)/lib/$(LIB_PREFIX)ipcdshared_s.$(LIB_SUFFIX) \
+ $(DIST)/lib/$(LIB_PREFIX)ipcdlock_s.$(LIB_SUFFIX) \
+ $(DIST)/lib/$(LIB_PREFIX)transmgr_s.$(LIB_SUFFIX) \
+ $(DIST)/lib/$(LIB_PREFIX)transmgrcom_s.$(LIB_SUFFIX) \
+ $(NULL)
+
+ifneq ($(BUILD_DCONNECT),)
+DEFINES += -DBUILD_DCONNECT
+LOCAL_INCLUDES += -I$(srcdir)/../../extensions/dconnect/src
+SHARED_LIBRARY_LIBS += $(DIST)/lib/$(LIB_PREFIX)ipcddconnect_s.$(LIB_SUFFIX) \
+ $(DIST)/lib/$(LIB_PREFIX)ipcdutil_s.$(LIB_SUFFIX) \
+ $(NULL)
+endif
+
+EXTRA_DSO_LDOPTS = \
+ $(LIBS_DIR) \
+ $(EXTRA_DSO_LIBS) \
+ $(MOZ_COMPONENT_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.kup
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnection.h b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnection.h
new file mode 100644
index 00000000..8773daa5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnection.h
@@ -0,0 +1,147 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by IBM Corporation are Copyright (C) 2003
+ * IBM Corporation. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcConnection_h__
+#define ipcConnection_h__
+
+#include "nscore.h"
+
+class ipcMessage;
+
+#define IPC_METHOD_PRIVATE_(type) NS_HIDDEN_(type)
+#define IPC_METHOD_PRIVATE IPC_METHOD_PRIVATE_(nsresult)
+
+/* ------------------------------------------------------------------------- */
+/* Platform specific IPC connection API.
+ */
+
+typedef void (* ipcCallbackFunc)(void *);
+
+/**
+ * IPC_Connect
+ *
+ * This function causes a connection to the IPC daemon to be established.
+ * If a connection already exists, then this function will be ignored.
+ *
+ * @param daemonPath
+ * Specifies the path to the IPC daemon executable.
+ *
+ * NOTE: This function must be called on the main thread.
+ */
+IPC_METHOD_PRIVATE IPC_Connect(const char *daemonPath);
+
+/**
+ * IPC_Disconnect
+ *
+ * This function causes a connection to the IPC daemon to be closed. Any
+ * unsent messages (IPC_SendMsg puts messages on a queue) will be sent to the
+ * IPC daemon before the connection is closed.
+ *
+ * NOTE: This function must be called on the main thread.
+ */
+IPC_METHOD_PRIVATE IPC_Disconnect();
+
+/**
+ * IPC_SendMsg
+ *
+ * This function sends a message to the IPC daemon. Typically, the message
+ * is put on a queue, to be delivered asynchronously to the IPC daemon. The
+ * ipcMessage object will be deleted when IPC_SendMsg is done with it. The
+ * caller must not touch |msg| after passing it to IPC_SendMsg.
+ *
+ * IPC_SendMsg cannot be called before IPC_Connect or after IPC_Disconnect.
+ *
+ * NOTE: This function may be called on any thread.
+ */
+IPC_METHOD_PRIVATE IPC_SendMsg(ipcMessage *msg);
+
+/**
+ * IPC_DoCallback
+ *
+ * This function executes a callback function on the same background thread
+ * that calls IPC_OnConnectionEnd and IPC_OnMessageAvailable.
+ *
+ * If this function succeeds, then the caller is guaranteed that |func| will
+ * be called. This guarantee is important because it allows the caller to
+ * free any memory associated with |arg| once |func| has been called.
+ *
+ * NOTE: This function may be called on any thread.
+ */
+IPC_METHOD_PRIVATE IPC_DoCallback(ipcCallbackFunc func, void *arg);
+
+/* ------------------------------------------------------------------------- */
+/* Cross-platform IPC connection methods.
+ */
+
+/**
+ * IPC_SpawnDaemon
+ *
+ * This function launches the IPC daemon process. It is called by the platform
+ * specific IPC_Connect implementation. It should not return until the daemon
+ * process is ready to receive a client connection or an error occurs.
+ *
+ * @param daemonPath
+ * Specifies the path to the IPC daemon executable.
+ */
+IPC_METHOD_PRIVATE IPC_SpawnDaemon(const char *daemonPath);
+
+/* ------------------------------------------------------------------------- */
+/* IPC connection callbacks (not implemented by the connection code).
+ *
+ * NOTE: These functions execute on a background thread!!
+ */
+
+/**
+ * IPC_OnConnectionEnd
+ *
+ * This function is called whenever the connection to the IPC daemon has been
+ * terminated. If terminated due to an abnormal error, then the error will be
+ * described by the |error| parameter. If |error| is NS_OK, then it means the
+ * connection was closed in response to a call to IPC_Disconnect.
+ */
+IPC_METHOD_PRIVATE_(void) IPC_OnConnectionEnd(nsresult error);
+
+/**
+ * IPC_OnMessageAvailable
+ *
+ * This function is called whenever an incoming message is read from the IPC
+ * daemon. The ipcMessage object, |msg|, must be deleted by the implementation
+ * of IPC_OnMessageAvailable when the object is no longer needed.
+ */
+IPC_METHOD_PRIVATE_(void) IPC_OnMessageAvailable(ipcMessage *msg);
+
+#endif // ipcConnection_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionStub.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionStub.cpp
new file mode 100644
index 00000000..8b985785
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionStub.cpp
@@ -0,0 +1,70 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by IBM Corporation are Copyright (C) 2003
+ * IBM Corporation. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcConnection.h"
+#include "nsError.h"
+
+//-----------------------------------------------------------------------------
+// use this file as a template to add client-side IPC connectivity.
+//
+// NOTE: if your platform supports local domain TCP sockets, then you should
+// be able to make use of ipcConnectionUnix.cpp.
+//-----------------------------------------------------------------------------
+
+nsresult
+IPC_Connect(const char *daemonPath)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+IPC_Disconnect()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+IPC_SendMsg(ipcMessage *msg)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+IPC_DoCallback(ipcCallbackFunc func, void *arg)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp
new file mode 100644
index 00000000..5cd7a0c8
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp
@@ -0,0 +1,615 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by IBM Corporation are Copyright (C) 2003
+ * IBM Corporation. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "private/pprio.h"
+#include "prerror.h"
+#include "prthread.h"
+#include "prlock.h"
+#include "prlog.h" // for PR_ASSERT (we don't actually use NSPR logging)
+#include "prio.h"
+
+#include "ipcConnection.h"
+#include "ipcMessageQ.h"
+#include "ipcConfig.h"
+#include "ipcLog.h"
+
+#ifdef VBOX
+# include "prenv.h"
+# include <stdio.h>
+# include <VBox/log.h>
+#endif
+
+
+//-----------------------------------------------------------------------------
+// NOTE: this code does not need to link with anything but NSPR. that is by
+// design, so it can be easily reused in other projects that want to
+// talk with mozilla's IPC daemon, but don't want to depend on xpcom.
+// we depend at most on some xpcom header files, but no xpcom runtime
+// symbols are used.
+//-----------------------------------------------------------------------------
+
+
+// single user systems, like OS/2, don't need these security checks.
+#ifndef XP_OS2
+#define IPC_SKIP_SECURITY_CHECKS
+#endif
+
+#ifndef IPC_SKIP_SECURITY_CHECKS
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
+
+static PRStatus
+DoSecurityCheck(PRFileDesc *fd, const char *path)
+{
+#ifndef IPC_SKIP_SECURITY_CHECKS
+ //
+ // now that we have a connected socket; do some security checks on the
+ // file descriptor.
+ //
+ // (1) make sure owner matches
+ // (2) make sure permissions match expected permissions
+ //
+ // if these conditions aren't met then bail.
+ //
+ int unix_fd = PR_FileDesc2NativeHandle(fd);
+
+ struct stat st;
+ if (fstat(unix_fd, &st) == -1) {
+ LOG(("stat failed"));
+ return PR_FAILURE;
+ }
+
+ if (st.st_uid != getuid() && st.st_uid != geteuid()) {
+ //
+ // on OSX 10.1.5, |fstat| has a bug when passed a file descriptor to
+ // a socket. it incorrectly returns a UID of 0. however, |stat|
+ // succeeds, but using |stat| introduces a race condition.
+ //
+ // XXX come up with a better security check.
+ //
+ if (st.st_uid != 0) {
+ LOG(("userid check failed"));
+ return PR_FAILURE;
+ }
+ if (stat(path, &st) == -1) {
+ LOG(("stat failed"));
+ return PR_FAILURE;
+ }
+ if (st.st_uid != getuid() && st.st_uid != geteuid()) {
+ LOG(("userid check failed"));
+ return PR_FAILURE;
+ }
+ }
+#endif
+ return PR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+
+struct ipcCallback : public ipcListNode<ipcCallback>
+{
+ ipcCallbackFunc func;
+ void *arg;
+};
+
+typedef ipcList<ipcCallback> ipcCallbackQ;
+
+//-----------------------------------------------------------------------------
+
+struct ipcConnectionState
+{
+ PRLock *lock;
+ PRPollDesc fds[2];
+ ipcCallbackQ callback_queue;
+ ipcMessageQ send_queue;
+ PRUint32 send_offset; // amount of send_queue.First() already written.
+ ipcMessage *in_msg;
+ PRBool shutdown;
+};
+
+#define SOCK 0
+#define POLL 1
+
+static void
+ConnDestroy(ipcConnectionState *s)
+{
+ if (s->lock)
+ PR_DestroyLock(s->lock);
+
+ if (s->fds[SOCK].fd)
+ PR_Close(s->fds[SOCK].fd);
+
+ if (s->fds[POLL].fd)
+ PR_DestroyPollableEvent(s->fds[POLL].fd);
+
+ if (s->in_msg)
+ delete s->in_msg;
+
+ s->send_queue.DeleteAll();
+ delete s;
+}
+
+static ipcConnectionState *
+ConnCreate(PRFileDesc *fd)
+{
+ ipcConnectionState *s = new ipcConnectionState;
+ if (!s)
+ return NULL;
+
+ s->lock = PR_NewLock();
+ s->fds[SOCK].fd = NULL;
+ s->fds[POLL].fd = PR_NewPollableEvent();
+ s->send_offset = 0;
+ s->in_msg = NULL;
+ s->shutdown = PR_FALSE;
+
+ if (!s->lock || !s->fds[1].fd)
+ {
+ ConnDestroy(s);
+ return NULL;
+ }
+
+ // disable inheritance of the IPC socket by children started
+ // using non-NSPR process API
+ PRStatus status = PR_SetFDInheritable(fd, PR_FALSE);
+ if (status != PR_SUCCESS)
+ {
+ LOG(("coudn't make IPC socket non-inheritable [err=%d]\n", PR_GetError()));
+ return NULL;
+ }
+
+ // store this only if we are going to succeed.
+ s->fds[SOCK].fd = fd;
+
+ return s;
+}
+
+static nsresult
+ConnRead(ipcConnectionState *s)
+{
+ char buf[1024];
+ nsresult rv = NS_OK;
+ PRInt32 n;
+
+ do
+ {
+ n = PR_Read(s->fds[SOCK].fd, buf, sizeof(buf));
+ if (n < 0)
+ {
+ PRErrorCode err = PR_GetError();
+ if (err == PR_WOULD_BLOCK_ERROR)
+ {
+ // socket is empty... we need to go back to polling.
+ break;
+ }
+ LOG(("PR_Read returned failure [err=%d]\n", err));
+ rv = NS_ERROR_UNEXPECTED;
+ }
+ else if (n == 0)
+ {
+ LOG(("PR_Read returned EOF\n"));
+ rv = NS_ERROR_UNEXPECTED;
+ }
+ else
+ {
+ const char *pdata = buf;
+ while (n)
+ {
+ PRUint32 bytesRead;
+ PRBool complete;
+
+ if (!s->in_msg)
+ {
+ s->in_msg = new ipcMessage;
+ if (!s->in_msg)
+ {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ break;
+ }
+ }
+
+ if (s->in_msg->ReadFrom(pdata, n, &bytesRead, &complete) != PR_SUCCESS)
+ {
+ LOG(("error reading IPC message\n"));
+ rv = NS_ERROR_UNEXPECTED;
+ break;
+ }
+
+ PR_ASSERT(PRUint32(n) >= bytesRead);
+ n -= bytesRead;
+ pdata += bytesRead;
+
+ if (complete)
+ {
+ // protect against weird re-entrancy cases...
+ ipcMessage *m = s->in_msg;
+ s->in_msg = NULL;
+
+ IPC_OnMessageAvailable(m);
+ }
+ }
+ }
+ }
+ while (NS_SUCCEEDED(rv));
+
+ return rv;
+}
+
+static nsresult
+ConnWrite(ipcConnectionState *s)
+{
+ nsresult rv = NS_OK;
+
+ PR_Lock(s->lock);
+
+ // write one message and then return.
+ if (s->send_queue.First())
+ {
+ PRInt32 n = PR_Write(s->fds[SOCK].fd,
+ s->send_queue.First()->MsgBuf() + s->send_offset,
+ s->send_queue.First()->MsgLen() - s->send_offset);
+ if (n <= 0)
+ {
+ PRErrorCode err = PR_GetError();
+ if (err == PR_WOULD_BLOCK_ERROR)
+ {
+ // socket is full... we need to go back to polling.
+ }
+ else
+ {
+ LOG(("error writing to socket [err=%d]\n", err));
+ rv = NS_ERROR_UNEXPECTED;
+ }
+ }
+ else
+ {
+ s->send_offset += n;
+ if (s->send_offset == s->send_queue.First()->MsgLen())
+ {
+ s->send_queue.DeleteFirst();
+ s->send_offset = 0;
+
+ // if the send queue is empty, then we need to stop trying to write.
+ if (s->send_queue.IsEmpty())
+ s->fds[SOCK].in_flags &= ~PR_POLL_WRITE;
+ }
+ }
+ }
+
+ PR_Unlock(s->lock);
+ return rv;
+}
+
+PR_STATIC_CALLBACK(void)
+ConnThread(void *arg)
+{
+ PRInt32 num;
+ nsresult rv = NS_OK;
+
+ ipcConnectionState *s = (ipcConnectionState *) arg;
+
+ // we monitor two file descriptors in this thread. the first (at index 0) is
+ // the socket connection with the IPC daemon. the second (at index 1) is the
+ // pollable event we monitor in order to know when to send messages to the
+ // IPC daemon.
+
+ s->fds[SOCK].in_flags = PR_POLL_READ;
+ s->fds[POLL].in_flags = PR_POLL_READ;
+
+ while (NS_SUCCEEDED(rv))
+ {
+ s->fds[SOCK].out_flags = 0;
+ s->fds[POLL].out_flags = 0;
+
+ //
+ // poll on the IPC socket and NSPR pollable event
+ //
+ num = PR_Poll(s->fds, 2, PR_INTERVAL_NO_TIMEOUT);
+ if (num > 0)
+ {
+ ipcCallbackQ cbs_to_run;
+
+ // check if something has been added to the send queue. if so, then
+ // acknowledge pollable event (wait should not block), and configure
+ // poll flags to find out when we can write.
+
+ if (s->fds[POLL].out_flags & PR_POLL_READ)
+ {
+ PR_WaitForPollableEvent(s->fds[POLL].fd);
+ PR_Lock(s->lock);
+
+ if (!s->send_queue.IsEmpty())
+ s->fds[SOCK].in_flags |= PR_POLL_WRITE;
+
+ if (!s->callback_queue.IsEmpty())
+ s->callback_queue.MoveTo(cbs_to_run);
+
+ PR_Unlock(s->lock);
+ }
+
+ // check if we can read...
+ if (s->fds[SOCK].out_flags & PR_POLL_READ)
+ rv = ConnRead(s);
+
+ // check if we can write...
+ if (s->fds[SOCK].out_flags & PR_POLL_WRITE)
+ rv = ConnWrite(s);
+
+ // check if we have callbacks to run
+ while (!cbs_to_run.IsEmpty())
+ {
+ ipcCallback *cb = cbs_to_run.First();
+ (cb->func)(cb->arg);
+ cbs_to_run.DeleteFirst();
+ }
+
+ // check if we should exit this thread. delay processing a shutdown
+ // request until after all queued up messages have been sent and until
+ // after all queued up callbacks have been run.
+ PR_Lock(s->lock);
+ if (s->shutdown && s->send_queue.IsEmpty() && s->callback_queue.IsEmpty())
+ rv = NS_ERROR_ABORT;
+ PR_Unlock(s->lock);
+ }
+ else
+ {
+ LOG(("PR_Poll returned error %d (%s), os error %d\n", PR_GetError(),
+ PR_ErrorToName(PR_GetError()), PR_GetOSError()));
+ rv = NS_ERROR_UNEXPECTED;
+ }
+ }
+
+ // notify termination of the IPC connection
+ if (rv == NS_ERROR_ABORT)
+ rv = NS_OK;
+ IPC_OnConnectionEnd(rv);
+
+ LOG(("IPC thread exiting\n"));
+}
+
+//-----------------------------------------------------------------------------
+// IPC connection API
+//-----------------------------------------------------------------------------
+
+static ipcConnectionState *gConnState = NULL;
+static PRThread *gConnThread = NULL;
+
+#ifdef DEBUG
+static PRThread *gMainThread = NULL;
+#endif
+
+nsresult
+TryConnect(PRFileDesc **result)
+{
+ PRFileDesc *fd;
+ PRNetAddr addr;
+ PRSocketOptionData opt;
+ // don't use NS_ERROR_FAILURE as we want to detect these kind of errors
+ // in the frontend
+ nsresult rv = NS_ERROR_SOCKET_FAIL;
+
+ fd = PR_OpenTCPSocket(PR_AF_LOCAL);
+ if (!fd)
+ goto end;
+
+ addr.local.family = PR_AF_LOCAL;
+ IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path));
+
+ // blocking connect... will fail if no one is listening.
+ if (PR_Connect(fd, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE)
+ goto end;
+
+#ifdef VBOX
+ if (PR_GetEnv("TESTBOX_UUID"))
+ fprintf(stderr, "IPC socket path: %s\n", addr.local.path);
+ LogRel(("IPC socket path: %s\n", addr.local.path));
+#endif
+
+ // make socket non-blocking
+ opt.option = PR_SockOpt_Nonblocking;
+ opt.value.non_blocking = PR_TRUE;
+ PR_SetSocketOption(fd, &opt);
+
+ // do some security checks on connection socket...
+ if (DoSecurityCheck(fd, addr.local.path) != PR_SUCCESS)
+ goto end;
+
+ *result = fd;
+ return NS_OK;
+
+end:
+ if (fd)
+ PR_Close(fd);
+
+ return rv;
+}
+
+nsresult
+IPC_Connect(const char *daemonPath)
+{
+ // synchronous connect, spawn daemon if necessary.
+
+ PRFileDesc *fd = NULL;
+ nsresult rv = NS_ERROR_FAILURE;
+
+ if (gConnState)
+ return NS_ERROR_ALREADY_INITIALIZED;
+
+ //
+ // here's the connection algorithm: try to connect to an existing daemon.
+ // if the connection fails, then spawn the daemon (wait for it to be ready),
+ // and then retry the connection. it is critical that the socket used to
+ // connect to the daemon not be inherited (this causes problems on RH9 at
+ // least).
+ //
+
+ rv = TryConnect(&fd);
+ if (NS_FAILED(rv))
+ {
+ nsresult rv1 = IPC_SpawnDaemon(daemonPath);
+ if (NS_SUCCEEDED(rv1) || rv != NS_ERROR_SOCKET_FAIL)
+ rv = rv1;
+ if (NS_SUCCEEDED(rv))
+ rv = TryConnect(&fd);
+ }
+
+ if (NS_FAILED(rv))
+ goto end;
+
+ //
+ // ok, we have a connection to the daemon!
+ //
+
+ // build connection state object
+ gConnState = ConnCreate(fd);
+ if (!gConnState)
+ {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ goto end;
+ }
+ fd = NULL; // connection state now owns the socket
+
+ gConnThread = PR_CreateThread(PR_USER_THREAD,
+ ConnThread,
+ gConnState,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+ if (!gConnThread)
+ {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ goto end;
+ }
+
+#ifdef DEBUG
+ gMainThread = PR_GetCurrentThread();
+#endif
+ return NS_OK;
+
+end:
+ if (gConnState)
+ {
+ ConnDestroy(gConnState);
+ gConnState = NULL;
+ }
+ if (fd)
+ PR_Close(fd);
+ return rv;
+}
+
+nsresult
+IPC_Disconnect()
+{
+ // Must disconnect on same thread used to connect!
+ PR_ASSERT(gMainThread == PR_GetCurrentThread());
+
+ if (!gConnState || !gConnThread)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ PR_Lock(gConnState->lock);
+ gConnState->shutdown = PR_TRUE;
+ PR_SetPollableEvent(gConnState->fds[POLL].fd);
+ PR_Unlock(gConnState->lock);
+
+ PR_JoinThread(gConnThread);
+
+ ConnDestroy(gConnState);
+
+ gConnState = NULL;
+ gConnThread = NULL;
+ return NS_OK;
+}
+
+nsresult
+IPC_SendMsg(ipcMessage *msg)
+{
+ if (!gConnState || !gConnThread)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ PR_Lock(gConnState->lock);
+ gConnState->send_queue.Append(msg);
+ PR_SetPollableEvent(gConnState->fds[POLL].fd);
+ PR_Unlock(gConnState->lock);
+
+ return NS_OK;
+}
+
+nsresult
+IPC_DoCallback(ipcCallbackFunc func, void *arg)
+{
+ if (!gConnState || !gConnThread)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ ipcCallback *callback = new ipcCallback;
+ if (!callback)
+ return NS_ERROR_OUT_OF_MEMORY;
+ callback->func = func;
+ callback->arg = arg;
+
+ PR_Lock(gConnState->lock);
+ gConnState->callback_queue.Append(callback);
+ PR_SetPollableEvent(gConnState->fds[POLL].fd);
+ PR_Unlock(gConnState->lock);
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+
+#ifdef TEST_STANDALONE
+
+void IPC_OnConnectionFault(nsresult rv)
+{
+ LOG(("IPC_OnConnectionFault [rv=%x]\n", rv));
+}
+
+void IPC_OnMessageAvailable(ipcMessage *msg)
+{
+ LOG(("IPC_OnMessageAvailable\n"));
+ delete msg;
+}
+
+int main()
+{
+ IPC_InitLog(">>>");
+ IPC_Connect("/builds/moz-trunk/seamonkey-debug-build/dist/bin/mozilla-ipcd");
+ IPC_Disconnect();
+ return 0;
+}
+
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionWin.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionWin.cpp
new file mode 100644
index 00000000..9a99c195
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionWin.cpp
@@ -0,0 +1,332 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <windows.h>
+
+#include "prprf.h"
+#include "prmon.h"
+#include "prthread.h"
+#include "plevent.h"
+
+#include "nsIServiceManager.h"
+#include "nsIEventQueue.h"
+#include "nsIEventQueueService.h"
+#include "nsAutoLock.h"
+
+#include "ipcConfig.h"
+#include "ipcLog.h"
+#include "ipcConnection.h"
+#include "ipcm.h"
+
+
+//-----------------------------------------------------------------------------
+// NOTE: this code does not need to link with anything but NSPR. that is by
+// design, so it can be easily reused in other projects that want to
+// talk with mozilla's IPC daemon, but don't want to depend on xpcom.
+// we depend at most on some xpcom header files, but no xpcom runtime
+// symbols are used.
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// windows message thread
+//-----------------------------------------------------------------------------
+
+#define IPC_WM_SENDMSG (WM_USER + 0x1)
+#define IPC_WM_CALLBACK (WM_USER + 0x2)
+#define IPC_WM_SHUTDOWN (WM_USER + 0x3)
+
+static nsresult ipcThreadStatus = NS_OK;
+static PRThread *ipcThread = NULL;
+static PRMonitor *ipcMonitor = NULL;
+static HWND ipcDaemonHwnd = NULL;
+static HWND ipcLocalHwnd = NULL;
+static PRBool ipcShutdown = PR_FALSE; // not accessed on message thread!!
+
+//-----------------------------------------------------------------------------
+// window proc
+//-----------------------------------------------------------------------------
+
+static LRESULT CALLBACK
+ipcThreadWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LOG(("got message [msg=%x wparam=%x lparam=%x]\n", uMsg, wParam, lParam));
+
+ if (uMsg == WM_COPYDATA) {
+ COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam;
+ if (cd && cd->lpData) {
+ ipcMessage *msg = new ipcMessage();
+ PRUint32 bytesRead;
+ PRBool complete;
+ PRStatus rv = msg->ReadFrom((const char *) cd->lpData, cd->cbData,
+ &bytesRead, &complete);
+ if (rv == PR_SUCCESS && complete)
+ IPC_OnMessageAvailable(msg); // takes ownership of msg
+ else {
+ LOG((" unable to deliver message [complete=%u]\n", complete));
+ delete msg;
+ }
+ }
+ return TRUE;
+ }
+
+ if (uMsg == IPC_WM_SENDMSG) {
+ ipcMessage *msg = (ipcMessage *) lParam;
+ if (msg) {
+ LOG((" sending message...\n"));
+ COPYDATASTRUCT cd;
+ cd.dwData = GetCurrentProcessId();
+ cd.cbData = (DWORD) msg->MsgLen();
+ cd.lpData = (PVOID) msg->MsgBuf();
+ SendMessageA(ipcDaemonHwnd, WM_COPYDATA, (WPARAM) hWnd, (LPARAM) &cd);
+ LOG((" done.\n"));
+ delete msg;
+ }
+ return 0;
+ }
+
+ if (uMsg == IPC_WM_CALLBACK) {
+ ipcCallbackFunc func = (ipcCallbackFunc) wParam;
+ void *arg = (void *) lParam;
+ (func)(arg);
+ return 0;
+ }
+
+ if (uMsg == IPC_WM_SHUTDOWN) {
+ IPC_OnConnectionEnd(NS_OK);
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+//-----------------------------------------------------------------------------
+// ipc thread functions
+//-----------------------------------------------------------------------------
+
+static void
+ipcThreadFunc(void *arg)
+{
+ LOG(("entering message thread\n"));
+
+ DWORD pid = GetCurrentProcessId();
+
+ WNDCLASS wc;
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = ipcThreadWindowProc;
+ wc.lpszClassName = IPC_CLIENT_WINDOW_CLASS;
+ RegisterClass(&wc);
+
+ char wName[sizeof(IPC_CLIENT_WINDOW_NAME_PREFIX) + 20];
+ PR_snprintf(wName, sizeof(wName), "%s%u", IPC_CLIENT_WINDOW_NAME_PREFIX, pid);
+
+ ipcLocalHwnd = CreateWindow(IPC_CLIENT_WINDOW_CLASS, wName,
+ 0, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
+
+ {
+ nsAutoMonitor mon(ipcMonitor);
+ if (!ipcLocalHwnd)
+ ipcThreadStatus = NS_ERROR_FAILURE;
+ mon.Notify();
+ }
+
+ if (ipcLocalHwnd) {
+ MSG msg;
+ while (GetMessage(&msg, ipcLocalHwnd, 0, 0))
+ DispatchMessage(&msg);
+
+ ipcShutdown = PR_TRUE; // assuming atomic memory write
+
+ DestroyWindow(ipcLocalHwnd);
+ ipcLocalHwnd = NULL;
+ }
+
+ LOG(("exiting message thread\n"));
+ return;
+}
+
+static PRStatus
+ipcThreadInit()
+{
+ if (ipcThread)
+ return PR_FAILURE;
+
+ ipcShutdown = PR_FALSE;
+
+ ipcMonitor = PR_NewMonitor();
+ if (!ipcMonitor)
+ return PR_FAILURE;
+
+ // spawn message thread
+ ipcThread = PR_CreateThread(PR_USER_THREAD, ipcThreadFunc, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD, 0);
+ if (!ipcThread) {
+ NS_WARNING("thread creation failed");
+ PR_DestroyMonitor(ipcMonitor);
+ ipcMonitor = NULL;
+ return PR_FAILURE;
+ }
+
+ // wait for hidden window to be created
+ {
+ nsAutoMonitor mon(ipcMonitor);
+ while (!ipcLocalHwnd && NS_SUCCEEDED(ipcThreadStatus))
+ mon.Wait();
+ }
+
+ if (NS_FAILED(ipcThreadStatus)) {
+ NS_WARNING("message thread failed");
+ return PR_FAILURE;
+ }
+
+ return PR_SUCCESS;
+}
+
+static PRStatus
+ipcThreadShutdown()
+{
+ if (PR_AtomicSet(&ipcShutdown, PR_TRUE) == PR_FALSE) {
+ LOG(("posting IPC_WM_SHUTDOWN message\n"));
+ PostMessage(ipcLocalHwnd, IPC_WM_SHUTDOWN, 0, 0);
+ }
+
+ LOG(("joining w/ message thread...\n"));
+ PR_JoinThread(ipcThread);
+ ipcThread = NULL;
+
+ //
+ // ok, now the message thread is dead
+ //
+
+ PR_DestroyMonitor(ipcMonitor);
+ ipcMonitor = NULL;
+
+ return PR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// windows specific IPC connection impl
+//-----------------------------------------------------------------------------
+
+nsresult
+IPC_Disconnect()
+{
+ LOG(("IPC_Disconnect\n"));
+
+ //XXX mHaveConnection = PR_FALSE;
+
+ if (!ipcDaemonHwnd)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ if (ipcThread)
+ ipcThreadShutdown();
+
+ // clear our reference to the daemon's HWND.
+ ipcDaemonHwnd = NULL;
+ return NS_OK;
+}
+
+nsresult
+IPC_Connect(const char *daemonPath)
+{
+ LOG(("IPC_Connect\n"));
+
+ NS_ENSURE_TRUE(ipcDaemonHwnd == NULL, NS_ERROR_ALREADY_INITIALIZED);
+ nsresult rv;
+
+ ipcDaemonHwnd = FindWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME);
+ if (!ipcDaemonHwnd) {
+ LOG((" daemon does not appear to be running\n"));
+ //
+ // daemon does not exist; spawn daemon...
+ //
+ rv = IPC_SpawnDaemon(daemonPath);
+ if (NS_FAILED(rv))
+ return rv;
+
+ ipcDaemonHwnd = FindWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME);
+ if (!ipcDaemonHwnd)
+ return NS_ERROR_FAILURE;
+ }
+
+ //
+ // delay creation of the message thread until we know the daemon exists.
+ //
+ if (!ipcThread && ipcThreadInit() != PR_SUCCESS) {
+ ipcDaemonHwnd = NULL;
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+IPC_SendMsg(ipcMessage *msg)
+{
+ LOG(("IPC_SendMsg\n"));
+
+ if (ipcShutdown) {
+ LOG(("unable to send message b/c message thread is shutdown\n"));
+ goto loser;
+ }
+ if (!PostMessage(ipcLocalHwnd, IPC_WM_SENDMSG, 0, (LPARAM) msg)) {
+ LOG((" PostMessage failed w/ error = %u\n", GetLastError()));
+ goto loser;
+ }
+ return NS_OK;
+loser:
+ delete msg;
+ return NS_ERROR_FAILURE;
+}
+
+nsresult
+IPC_DoCallback(ipcCallbackFunc func, void *arg)
+{
+ LOG(("IPC_DoCallback\n"));
+
+ if (ipcShutdown) {
+ LOG(("unable to send message b/c message thread is shutdown\n"));
+ return NS_ERROR_FAILURE;
+ }
+ if (!PostMessage(ipcLocalHwnd, IPC_WM_CALLBACK, (WPARAM) func, (LPARAM) arg)) {
+ LOG((" PostMessage failed w/ error = %u\n", GetLastError()));
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcModuleFactory.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcModuleFactory.cpp
new file mode 100644
index 00000000..7dcd6eab
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcModuleFactory.cpp
@@ -0,0 +1,196 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIServiceManager.h"
+#include "nsIGenericFactory.h"
+#include "nsICategoryManager.h"
+#include "ipcdclient.h"
+#include "ipcService.h"
+#include "ipcConfig.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(ipcService)
+
+// enable this code to make the IPC service auto-start.
+#if 0
+NS_METHOD
+ipcServiceRegisterProc(nsIComponentManager *aCompMgr,
+ nsIFile *aPath,
+ const char *registryLocation,
+ const char *componentType,
+ const nsModuleComponentInfo *info)
+{
+ //
+ // add ipcService to the XPCOM startup category
+ //
+ nsCOMPtr<nsICategoryManager> catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
+ if (catman) {
+ nsXPIDLCString prevEntry;
+ catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcService",
+ IPC_SERVICE_CONTRACTID, PR_TRUE, PR_TRUE,
+ getter_Copies(prevEntry));
+ }
+ return NS_OK;
+}
+
+NS_METHOD
+ipcServiceUnregisterProc(nsIComponentManager *aCompMgr,
+ nsIFile *aPath,
+ const char *registryLocation,
+ const nsModuleComponentInfo *info)
+{
+ nsCOMPtr<nsICategoryManager> catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
+ if (catman)
+ catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID,
+ IPC_SERVICE_CONTRACTID, PR_TRUE);
+ return NS_OK;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// extensions
+
+#include "ipcLockService.h"
+#include "ipcLockCID.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcLockService, Init)
+
+#include "tmTransactionService.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService)
+
+#ifdef BUILD_DCONNECT
+
+#include "ipcDConnectService.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcDConnectService, Init)
+
+// enable this code to make the IPC DCONNECT service auto-start.
+NS_METHOD
+ipcDConnectServiceRegisterProc(nsIComponentManager *aCompMgr,
+ nsIFile *aPath,
+ const char *registryLocation,
+ const char *componentType,
+ const nsModuleComponentInfo *info)
+{
+ //
+ // add ipcService to the XPCOM startup category
+ //
+ nsCOMPtr<nsICategoryManager> catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
+ if (catman) {
+ nsXPIDLCString prevEntry;
+ catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcDConnectService",
+ IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE, PR_TRUE,
+ getter_Copies(prevEntry));
+ }
+ return NS_OK;
+}
+
+NS_METHOD
+ipcDConnectServiceUnregisterProc(nsIComponentManager *aCompMgr,
+ nsIFile *aPath,
+ const char *registryLocation,
+ const nsModuleComponentInfo *info)
+{
+ nsCOMPtr<nsICategoryManager> catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
+ if (catman)
+ catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID,
+ IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE);
+ return NS_OK;
+}
+
+#endif // BUILD_DCONNECT
+
+//-----------------------------------------------------------------------------
+// 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 },
+ /*
+ ipcServiceRegisterProc,
+ ipcServiceUnregisterProc },
+ */
+ //
+ // extensions go here:
+ //
+ { IPC_LOCKSERVICE_CLASSNAME,
+ IPC_LOCKSERVICE_CID,
+ IPC_LOCKSERVICE_CONTRACTID,
+ ipcLockServiceConstructor },
+ { IPC_TRANSACTIONSERVICE_CLASSNAME,
+ IPC_TRANSACTIONSERVICE_CID,
+ IPC_TRANSACTIONSERVICE_CONTRACTID,
+ tmTransactionServiceConstructor },
+
+#ifdef BUILD_DCONNECT
+ { IPC_DCONNECTSERVICE_CLASSNAME,
+ IPC_DCONNECTSERVICE_CID,
+ IPC_DCONNECTSERVICE_CONTRACTID,
+ ipcDConnectServiceConstructor,
+ ipcDConnectServiceRegisterProc,
+ ipcDConnectServiceUnregisterProc },
+#endif
+};
+
+//-----------------------------------------------------------------------------
+
+PR_STATIC_CALLBACK(nsresult)
+ipcdclient_init(nsIModule *module)
+{
+ return IPC_Init();
+}
+
+PR_STATIC_CALLBACK(void)
+ipcdclient_shutdown(nsIModule *module)
+{
+ IPC_Shutdown();
+}
+
+//-----------------------------------------------------------------------------
+// Implement the NSGetModule() exported function for your module
+// and the entire implementation of the module object.
+//-----------------------------------------------------------------------------
+NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(ipcdclient, components,
+ ipcdclient_init,
+ ipcdclient_shutdown)
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.cpp
new file mode 100644
index 00000000..6c2a1326
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.cpp
@@ -0,0 +1,120 @@
+/* vim:set ts=4 sw=4 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcService.h"
+
+// The ipcService implementation is nothing more than a thin XPCOM wrapper
+// around the ipcdclient.h API.
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(ipcService, ipcIService)
+
+NS_IMETHODIMP
+ipcService::GetID(PRUint32 *aID)
+{
+ return IPC_GetID(aID);
+}
+
+NS_IMETHODIMP
+ipcService::AddName(const char *aName)
+{
+ return IPC_AddName(aName);
+}
+
+NS_IMETHODIMP
+ipcService::RemoveName(const char *aName)
+{
+ return IPC_RemoveName(aName);
+}
+
+NS_IMETHODIMP
+ipcService::AddClientObserver(ipcIClientObserver *aObserver)
+{
+ return IPC_AddClientObserver(aObserver);
+}
+
+NS_IMETHODIMP
+ipcService::RemoveClientObserver(ipcIClientObserver *aObserver)
+{
+ return IPC_RemoveClientObserver(aObserver);
+}
+
+NS_IMETHODIMP
+ipcService::ResolveClientName(const char *aName, PRUint32 *aID)
+{
+ return IPC_ResolveClientName(aName, aID);
+}
+
+NS_IMETHODIMP
+ipcService::ClientExists(PRUint32 aClientID, PRBool *aResult)
+{
+ return IPC_ClientExists(aClientID, aResult);
+}
+
+NS_IMETHODIMP
+ipcService::DefineTarget(const nsID &aTarget, ipcIMessageObserver *aObserver,
+ PRBool aOnCurrentThread)
+{
+ return IPC_DefineTarget(aTarget, aObserver, aOnCurrentThread);
+}
+
+NS_IMETHODIMP
+ipcService::SendMessage(PRUint32 aReceiverID, const nsID &aTarget,
+ const PRUint8 *aData, PRUint32 aDataLen)
+{
+ return IPC_SendMessage(aReceiverID, aTarget, aData, aDataLen);
+}
+
+NS_IMETHODIMP
+ipcService::WaitMessage(PRUint32 aSenderID, const nsID &aTarget,
+ ipcIMessageObserver *aObserver,
+ PRUint32 aTimeout)
+{
+ return IPC_WaitMessage(aSenderID, aTarget, aObserver, nsnull,
+ PR_MillisecondsToInterval(aTimeout));
+}
+
+NS_IMETHODIMP
+ipcService::DisableMessageObserver(const nsID &aTarget)
+{
+ return IPC_DisableMessageObserver(aTarget);
+}
+
+NS_IMETHODIMP
+ipcService::EnableMessageObserver(const nsID &aTarget)
+{
+ return IPC_EnableMessageObserver(aTarget);
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.h b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.h
new file mode 100644
index 00000000..80f953cf
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.h
@@ -0,0 +1,51 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcService_h__
+#define ipcService_h__
+
+#include "ipcIService.h"
+#include "ipcdclient.h"
+
+class ipcService : public ipcIService
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_IPCISERVICE
+};
+
+#endif // !defined( ipcService_h__ )
diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp
new file mode 100644
index 00000000..ce0f86c8
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp
@@ -0,0 +1,1505 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcdclient.h"
+#include "ipcConnection.h"
+#include "ipcConfig.h"
+#include "ipcMessageQ.h"
+#include "ipcMessageUtils.h"
+#include "ipcLog.h"
+#include "ipcm.h"
+
+#include "nsIFile.h"
+#include "nsEventQueueUtils.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsCOMPtr.h"
+#include "nsHashKeys.h"
+#include "nsRefPtrHashtable.h"
+#include "nsAutoLock.h"
+#include "nsProxyRelease.h"
+#include "nsCOMArray.h"
+
+#include "prio.h"
+#include "prproces.h"
+#include "pratom.h"
+
+#ifdef VBOX
+# include <iprt/critsect.h>
+# define VBOX_WITH_IPCCLIENT_RW_CS
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#define IPC_REQUEST_TIMEOUT PR_SecondsToInterval(30)
+
+/* ------------------------------------------------------------------------- */
+
+class ipcTargetData
+{
+public:
+ static NS_HIDDEN_(ipcTargetData*) Create();
+
+ // threadsafe addref/release
+ NS_HIDDEN_(nsrefcnt) AddRef() { return PR_AtomicIncrement(&refcnt); }
+ NS_HIDDEN_(nsrefcnt) Release() { PRInt32 r = PR_AtomicDecrement(&refcnt); if (r == 0) delete this; return r; }
+
+ NS_HIDDEN_(void) SetObserver(ipcIMessageObserver *aObserver, PRBool aOnCurrentThread);
+
+ // protects access to the members of this class
+ PRMonitor *monitor;
+
+ // this may be null
+ nsCOMPtr<ipcIMessageObserver> observer;
+
+ // the message observer is called via this event queue
+ nsCOMPtr<nsIEventQueue> eventQ;
+
+ // incoming messages are added to this list
+ ipcMessageQ pendingQ;
+
+ // non-zero if the observer has been disabled (this means that new messages
+ // should not be dispatched to the observer until the observer is re-enabled
+ // via IPC_EnableMessageObserver).
+ PRInt32 observerDisabled;
+
+private:
+
+ ipcTargetData()
+ : monitor(nsAutoMonitor::NewMonitor("ipcTargetData"))
+ , observerDisabled(0)
+ , refcnt(0)
+ {}
+
+ ~ipcTargetData()
+ {
+ if (monitor)
+ nsAutoMonitor::DestroyMonitor(monitor);
+ }
+
+ PRInt32 refcnt;
+};
+
+ipcTargetData *
+ipcTargetData::Create()
+{
+ ipcTargetData *td = new ipcTargetData;
+ if (!td)
+ return NULL;
+
+ if (!td->monitor)
+ {
+ delete td;
+ return NULL;
+ }
+ return td;
+}
+
+void
+ipcTargetData::SetObserver(ipcIMessageObserver *aObserver, PRBool aOnCurrentThread)
+{
+ observer = aObserver;
+
+ if (aOnCurrentThread)
+ NS_GetCurrentEventQ(getter_AddRefs(eventQ));
+ else
+ eventQ = nsnull;
+}
+
+/* ------------------------------------------------------------------------- */
+
+typedef nsRefPtrHashtable<nsIDHashKey, ipcTargetData> ipcTargetMap;
+
+class ipcClientState
+{
+public:
+ static NS_HIDDEN_(ipcClientState *) Create();
+
+ ~ipcClientState()
+ {
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ if (monitor)
+ nsAutoMonitor::DestroyMonitor(monitor);
+#else
+ RTCritSectRwDelete(&critSect);
+#endif
+ }
+
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ //
+ // the monitor protects the targetMap and the connected and shutdown flags.
+ //
+ // NOTE: we use a PRMonitor for this instead of a PRLock because we need
+ // the lock to be re-entrant. since we don't ever need to wait on
+ // this monitor, it might be worth it to implement a re-entrant
+ // wrapper for PRLock.
+ //
+ PRMonitor *monitor;
+#else /* VBOX_WITH_IPCCLIENT_RW_CS */
+ RTCRITSECTRW critSect;
+#endif /* VBOX_WITH_IPCCLIENT_RW_CS */
+ ipcTargetMap targetMap;
+ PRBool connected;
+ PRBool shutdown;
+
+ // our process's client id
+ PRUint32 selfID;
+
+ nsCOMArray<ipcIClientObserver> clientObservers;
+
+private:
+
+ ipcClientState()
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ : monitor(nsAutoMonitor::NewMonitor("ipcClientState"))
+ , connected(PR_FALSE)
+#else
+ : connected(PR_FALSE)
+#endif
+ , shutdown(PR_FALSE)
+ , selfID(0)
+ {
+#ifdef VBOX_WITH_IPCCLIENT_RW_CS
+ /* Not employing the lock validator here to keep performance up in debug builds. */
+ RTCritSectRwInitEx(&critSect, RTCRITSECT_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
+#endif
+ }
+};
+
+ipcClientState *
+ipcClientState::Create()
+{
+ ipcClientState *cs = new ipcClientState;
+ if (!cs)
+ return NULL;
+
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ if (!cs->monitor || !cs->targetMap.Init())
+#else
+ if (!RTCritSectRwIsInitialized(&cs->critSect) || !cs->targetMap.Init())
+#endif
+ {
+ delete cs;
+ return NULL;
+ }
+
+ return cs;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static ipcClientState *gClientState;
+
+static PRBool
+GetTarget(const nsID &aTarget, ipcTargetData **td)
+{
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ nsAutoMonitor mon(gClientState->monitor);
+ return gClientState->targetMap.Get(nsIDHashKey(&aTarget).GetKey(), td);
+#else
+ RTCritSectRwEnterShared(&gClientState->critSect);
+ PRBool fRc = gClientState->targetMap.Get(nsIDHashKey(&aTarget).GetKey(), td);
+ RTCritSectRwLeaveShared(&gClientState->critSect);
+ return fRc;
+#endif
+}
+
+static PRBool
+PutTarget(const nsID &aTarget, ipcTargetData *td)
+{
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ nsAutoMonitor mon(gClientState->monitor);
+ return gClientState->targetMap.Put(nsIDHashKey(&aTarget).GetKey(), td);
+#else
+ RTCritSectRwEnterExcl(&gClientState->critSect);
+ PRBool fRc = gClientState->targetMap.Put(nsIDHashKey(&aTarget).GetKey(), td);
+ RTCritSectRwLeaveExcl(&gClientState->critSect);
+ return fRc;
+#endif
+}
+
+static void
+DelTarget(const nsID &aTarget)
+{
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ nsAutoMonitor mon(gClientState->monitor);
+ gClientState->targetMap.Remove(nsIDHashKey(&aTarget).GetKey());
+#else
+ RTCritSectRwEnterExcl(&gClientState->critSect);
+ gClientState->targetMap.Remove(nsIDHashKey(&aTarget).GetKey());
+ RTCritSectRwLeaveExcl(&gClientState->critSect);
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+
+static nsresult
+GetDaemonPath(nsCString &dpath)
+{
+ nsCOMPtr<nsIFile> file;
+
+ nsresult rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
+ getter_AddRefs(file));
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = file->AppendNative(NS_LITERAL_CSTRING(IPC_DAEMON_APP_NAME));
+ if (NS_SUCCEEDED(rv))
+ rv = file->GetNativePath(dpath);
+ }
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+ProcessPendingQ(const nsID &aTarget)
+{
+ ipcMessageQ tempQ;
+
+ nsRefPtr<ipcTargetData> td;
+ if (GetTarget(aTarget, getter_AddRefs(td)))
+ {
+ nsAutoMonitor mon(td->monitor);
+
+ // if the observer for this target has been temporarily disabled, then
+ // we must not processing any pending messages at this time.
+
+ if (!td->observerDisabled)
+ td->pendingQ.MoveTo(tempQ);
+ }
+
+ // process pending queue outside monitor
+ while (!tempQ.IsEmpty())
+ {
+ ipcMessage *msg = tempQ.First();
+
+ // it is possible that messages for other targets are in the queue
+ // (currently, this can be only a IPCM_MSG_PSH_CLIENT_STATE message
+ // initially addressed to IPCM_TARGET, see IPC_OnMessageAvailable())
+ // --ignore them.
+ if (td->observer && msg->Target().Equals(aTarget))
+ td->observer->OnMessageAvailable(msg->mMetaData,
+ msg->Target(),
+ (const PRUint8 *) msg->Data(),
+ msg->DataLen());
+ else
+ {
+ // the IPCM target does not have an observer, and therefore any IPCM
+ // messages that make it here will simply be dropped.
+ NS_ASSERTION(aTarget.Equals(IPCM_TARGET) || msg->Target().Equals(IPCM_TARGET),
+ "unexpected target");
+ LOG(("dropping IPCM message: type=%x\n", IPCM_GetType(msg)));
+ }
+ tempQ.DeleteFirst();
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+// WaitTarget enables support for multiple threads blocking on the same
+// message target. the selector is called while inside the target's monitor.
+
+typedef nsresult (* ipcMessageSelector)(
+ void *arg,
+ ipcTargetData *td,
+ const ipcMessage *msg
+);
+
+// selects any
+static nsresult
+DefaultSelector(void *arg, ipcTargetData *td, const ipcMessage *msg)
+{
+ return NS_OK;
+}
+
+static nsresult
+WaitTarget(const nsID &aTarget,
+ PRIntervalTime aTimeout,
+ ipcMessage **aMsg,
+ ipcMessageSelector aSelector = nsnull,
+ void *aArg = nsnull)
+{
+ *aMsg = nsnull;
+
+ if (!aSelector)
+ aSelector = DefaultSelector;
+
+ nsRefPtr<ipcTargetData> td;
+ if (!GetTarget(aTarget, getter_AddRefs(td)))
+ return NS_ERROR_INVALID_ARG; // bad aTarget
+
+ PRBool isIPCMTarget = aTarget.Equals(IPCM_TARGET);
+
+ PRIntervalTime timeStart = PR_IntervalNow();
+ PRIntervalTime timeEnd;
+ if (aTimeout == PR_INTERVAL_NO_TIMEOUT)
+ timeEnd = aTimeout;
+ else if (aTimeout == PR_INTERVAL_NO_WAIT)
+ timeEnd = timeStart;
+ else
+ {
+ timeEnd = timeStart + aTimeout;
+
+ // if overflowed, then set to max value
+ if (timeEnd < timeStart)
+ timeEnd = PR_INTERVAL_NO_TIMEOUT;
+ }
+
+ ipcMessage *lastChecked = nsnull, *beforeLastChecked = nsnull;
+ nsresult rv = NS_ERROR_ABORT;
+
+ nsAutoMonitor mon(td->monitor);
+
+ // only the ICPM target is allowed to wait for a message after shutdown
+ // (but before disconnection). this gives client observers called from
+ // IPC_Shutdown a chance to use IPC_SendMessage to send necessary
+ // "last minute" messages to other clients.
+
+ while (gClientState->connected && (!gClientState->shutdown || isIPCMTarget))
+ {
+ NS_ASSERTION(!lastChecked, "oops");
+
+ //
+ // NOTE:
+ //
+ // we must start at the top of the pending queue, possibly revisiting
+ // messages that our selector has already rejected. this is necessary
+ // because the queue may have been modified while we were waiting on
+ // the monitor. the impact of this on performance remains to be seen.
+ //
+ // one cheap solution is to keep a counter that is incremented each
+ // time a message is removed from the pending queue. that way we can
+ // avoid revisiting all messages sometimes.
+ //
+
+ lastChecked = td->pendingQ.First();
+ beforeLastChecked = nsnull;
+
+ // loop over pending queue until we find a message that our selector likes.
+ while (lastChecked)
+ {
+ //
+ // it is possible that this call to WaitTarget() has been initiated by
+ // some other selector, that might be currently processing the same
+ // message (since the message remains in the queue until the selector
+ // returns TRUE). here we prevent this situation by using a special flag
+ // to guarantee that every message is processed only once.
+ //
+
+ if (!lastChecked->TestFlag(IPC_MSG_FLAG_IN_PROCESS))
+ {
+ lastChecked->SetFlag(IPC_MSG_FLAG_IN_PROCESS);
+ nsresult acceptedRV = (aSelector)(aArg, td, lastChecked);
+ lastChecked->ClearFlag(IPC_MSG_FLAG_IN_PROCESS);
+
+ if (acceptedRV != IPC_WAIT_NEXT_MESSAGE)
+ {
+ if (acceptedRV == NS_OK)
+ {
+ // remove from pending queue
+ if (beforeLastChecked)
+ td->pendingQ.RemoveAfter(beforeLastChecked);
+ else
+ td->pendingQ.RemoveFirst();
+
+ lastChecked->mNext = nsnull;
+ *aMsg = lastChecked;
+ break;
+ }
+ else /* acceptedRV == IPC_DISCARD_MESSAGE */
+ {
+ ipcMessage *nextToCheck = lastChecked->mNext;
+
+ // discard from pending queue
+ if (beforeLastChecked)
+ td->pendingQ.DeleteAfter(beforeLastChecked);
+ else
+ td->pendingQ.DeleteFirst();
+
+ lastChecked = nextToCheck;
+
+ continue;
+ }
+ }
+ }
+
+ beforeLastChecked = lastChecked;
+ lastChecked = lastChecked->mNext;
+ }
+
+ if (*aMsg)
+ {
+ rv = NS_OK;
+ break;
+ }
+#ifdef VBOX
+ else
+ {
+ /* Special client liveness check if there is no message to process.
+ * This is necessary as there might be several threads waiting for
+ * a message from a single client, and only one gets the DOWN msg. */
+ nsresult aliveRV = (aSelector)(aArg, td, NULL);
+ if (aliveRV != IPC_WAIT_NEXT_MESSAGE)
+ {
+ *aMsg = NULL;
+ break;
+ }
+ }
+#endif /* VBOX */
+
+ PRIntervalTime t = PR_IntervalNow();
+ if (t > timeEnd) // check if timeout has expired
+ {
+ rv = IPC_ERROR_WOULD_BLOCK;
+ break;
+ }
+ mon.Wait(timeEnd - t);
+
+ LOG(("woke up from sleep [pendingQempty=%d connected=%d shutdown=%d isIPCMTarget=%d]\n",
+ td->pendingQ.IsEmpty(), gClientState->connected,
+ gClientState->shutdown, isIPCMTarget));
+ }
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+PostEvent(nsIEventTarget *eventTarget, PLEvent *ev)
+{
+ if (!ev)
+ return;
+
+ nsresult rv = eventTarget->PostEvent(ev);
+ if (NS_FAILED(rv))
+ {
+ NS_WARNING("PostEvent failed");
+ PL_DestroyEvent(ev);
+ }
+}
+
+static void
+PostEventToMainThread(PLEvent *ev)
+{
+ nsCOMPtr<nsIEventQueue> eventQ;
+ NS_GetMainEventQ(getter_AddRefs(eventQ));
+ if (!eventQ)
+ {
+ NS_WARNING("unable to get reference to main event queue");
+ PL_DestroyEvent(ev);
+ return;
+ }
+ PostEvent(eventQ, ev);
+}
+
+/* ------------------------------------------------------------------------- */
+
+class ipcEvent_ClientState : public PLEvent
+{
+public:
+ ipcEvent_ClientState(PRUint32 aClientID, PRUint32 aClientState)
+ : mClientID(aClientID)
+ , mClientState(aClientState)
+ {
+ PL_InitEvent(this, nsnull, HandleEvent, DestroyEvent);
+ }
+
+ PR_STATIC_CALLBACK(void *) HandleEvent(PLEvent *ev)
+ {
+ // maybe we've been shutdown!
+ if (!gClientState)
+ return nsnull;
+
+ ipcEvent_ClientState *self = (ipcEvent_ClientState *) ev;
+
+ for (PRInt32 i=0; i<gClientState->clientObservers.Count(); ++i)
+ gClientState->clientObservers[i]->OnClientStateChange(self->mClientID,
+ self->mClientState);
+ return nsnull;
+ }
+
+ PR_STATIC_CALLBACK(void) DestroyEvent(PLEvent *ev)
+ {
+ delete (ipcEvent_ClientState *) ev;
+ }
+
+private:
+ PRUint32 mClientID;
+ PRUint32 mClientState;
+};
+
+/* ------------------------------------------------------------------------- */
+
+class ipcEvent_ProcessPendingQ : public PLEvent
+{
+public:
+ ipcEvent_ProcessPendingQ(const nsID &aTarget)
+ : mTarget(aTarget)
+ {
+ PL_InitEvent(this, nsnull, HandleEvent, DestroyEvent);
+ }
+
+ PR_STATIC_CALLBACK(void *) HandleEvent(PLEvent *ev)
+ {
+ ProcessPendingQ(((ipcEvent_ProcessPendingQ *) ev)->mTarget);
+ return nsnull;
+ }
+
+ PR_STATIC_CALLBACK(void) DestroyEvent(PLEvent *ev)
+ {
+ delete (ipcEvent_ProcessPendingQ *) ev;
+ }
+
+private:
+ const nsID mTarget;
+};
+
+static void
+CallProcessPendingQ(const nsID &target, ipcTargetData *td)
+{
+ // we assume that we are inside td's monitor
+
+ PLEvent *ev = new ipcEvent_ProcessPendingQ(target);
+ if (!ev)
+ return;
+
+ nsresult rv;
+
+ if (td->eventQ)
+ rv = td->eventQ->PostEvent(ev);
+ else
+ rv = IPC_DoCallback((ipcCallbackFunc) PL_HandleEvent, ev);
+
+ if (NS_FAILED(rv))
+ PL_DestroyEvent(ev);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+DisableMessageObserver(const nsID &aTarget)
+{
+ nsRefPtr<ipcTargetData> td;
+ if (GetTarget(aTarget, getter_AddRefs(td)))
+ {
+ nsAutoMonitor mon(td->monitor);
+ ++td->observerDisabled;
+ }
+}
+
+static void
+EnableMessageObserver(const nsID &aTarget)
+{
+ nsRefPtr<ipcTargetData> td;
+ if (GetTarget(aTarget, getter_AddRefs(td)))
+ {
+ nsAutoMonitor mon(td->monitor);
+ if (td->observerDisabled > 0 && --td->observerDisabled == 0)
+ if (!td->pendingQ.IsEmpty())
+ CallProcessPendingQ(aTarget, td);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+// converts IPCM_ERROR_* status codes to NS_ERROR_* status codes
+static nsresult nsresult_from_ipcm_result(PRInt32 status)
+{
+ nsresult rv = NS_ERROR_FAILURE;
+
+ switch (status)
+ {
+ case IPCM_ERROR_GENERIC: rv = NS_ERROR_FAILURE; break;
+ case IPCM_ERROR_INVALID_ARG: rv = NS_ERROR_INVALID_ARG; break;
+ case IPCM_ERROR_NO_CLIENT: rv = NS_ERROR_CALL_FAILED; break;
+ // TODO: select better mapping for the below codes
+ case IPCM_ERROR_NO_SUCH_DATA:
+ case IPCM_ERROR_ALREADY_EXISTS: rv = NS_ERROR_FAILURE; break;
+ default: NS_ASSERTION(PR_FALSE, "No conversion");
+ }
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------------- */
+
+// selects the next IPCM message with matching request index
+static nsresult
+WaitIPCMResponseSelector(void *arg, ipcTargetData *td, const ipcMessage *msg)
+{
+#ifdef VBOX
+ if (!msg)
+ return IPC_WAIT_NEXT_MESSAGE;
+#endif /* VBOX */
+ PRUint32 requestIndex = *(PRUint32 *) arg;
+ return IPCM_GetRequestIndex(msg) == requestIndex ? NS_OK : IPC_WAIT_NEXT_MESSAGE;
+}
+
+// wait for an IPCM response message. if responseMsg is null, then it is
+// assumed that the caller does not care to get a reference to the
+// response itself. if the response is an IPCM_MSG_ACK_RESULT, then the
+// status code is mapped to a nsresult and returned by this function.
+static nsresult
+WaitIPCMResponse(PRUint32 requestIndex, ipcMessage **responseMsg = nsnull)
+{
+ ipcMessage *msg;
+
+ nsresult rv = WaitTarget(IPCM_TARGET, IPC_REQUEST_TIMEOUT, &msg,
+ WaitIPCMResponseSelector, &requestIndex);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (IPCM_GetType(msg) == IPCM_MSG_ACK_RESULT)
+ {
+ ipcMessageCast<ipcmMessageResult> result(msg);
+ if (result->Status() < 0)
+ rv = nsresult_from_ipcm_result(result->Status());
+ else
+ rv = NS_OK;
+ }
+
+ if (responseMsg)
+ *responseMsg = msg;
+ else
+ delete msg;
+
+ return rv;
+}
+
+// make an IPCM request and wait for a response.
+static nsresult
+MakeIPCMRequest(ipcMessage *msg, ipcMessage **responseMsg = nsnull)
+{
+ if (!msg)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ PRUint32 requestIndex = IPCM_GetRequestIndex(msg);
+
+ // suppress 'ProcessPendingQ' for IPCM messages until we receive the
+ // response to this IPCM request. if we did not do this then there
+ // would be a race condition leading to the possible removal of our
+ // response from the pendingQ between sending the request and waiting
+ // for the response.
+ DisableMessageObserver(IPCM_TARGET);
+
+ nsresult rv = IPC_SendMsg(msg);
+ if (NS_SUCCEEDED(rv))
+ rv = WaitIPCMResponse(requestIndex, responseMsg);
+
+ EnableMessageObserver(IPCM_TARGET);
+ return rv;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+RemoveTarget(const nsID &aTarget, PRBool aNotifyDaemon)
+{
+ DelTarget(aTarget);
+
+ if (aNotifyDaemon)
+ {
+ nsresult rv = MakeIPCMRequest(new ipcmMessageClientDelTarget(aTarget));
+ if (NS_FAILED(rv))
+ LOG(("failed to delete target: rv=%x\n", rv));
+ }
+}
+
+static nsresult
+DefineTarget(const nsID &aTarget,
+ ipcIMessageObserver *aObserver,
+ PRBool aOnCurrentThread,
+ PRBool aNotifyDaemon,
+ ipcTargetData **aResult)
+{
+ nsresult rv;
+
+ nsRefPtr<ipcTargetData> td( ipcTargetData::Create() );
+ if (!td)
+ return NS_ERROR_OUT_OF_MEMORY;
+ td->SetObserver(aObserver, aOnCurrentThread);
+
+ if (!PutTarget(aTarget, td))
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ if (aNotifyDaemon)
+ {
+ rv = MakeIPCMRequest(new ipcmMessageClientAddTarget(aTarget));
+ if (NS_FAILED(rv))
+ {
+ LOG(("failed to add target: rv=%x\n", rv));
+ RemoveTarget(aTarget, PR_FALSE);
+ return rv;
+ }
+ }
+
+ if (aResult)
+ NS_ADDREF(*aResult = td);
+ return NS_OK;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static nsresult
+TryConnect()
+{
+ nsCAutoString dpath;
+ nsresult rv = GetDaemonPath(dpath);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = IPC_Connect(dpath.get());
+ if (NS_FAILED(rv))
+ return rv;
+
+ gClientState->connected = PR_TRUE;
+
+ rv = DefineTarget(IPCM_TARGET, nsnull, PR_FALSE, PR_FALSE, nsnull);
+ if (NS_FAILED(rv))
+ return rv;
+
+ ipcMessage *msg = NULL;
+
+ // send CLIENT_HELLO and wait for CLIENT_ID response...
+ rv = MakeIPCMRequest(new ipcmMessageClientHello(), &msg);
+ if (NS_FAILED(rv))
+ {
+#ifdef VBOX /* MakeIPCMRequest may return a failure (e.g. NS_ERROR_CALL_FAILED) and a response msg. */
+ if (msg)
+ delete msg;
+#endif
+ return rv;
+ }
+
+ if (IPCM_GetType(msg) == IPCM_MSG_ACK_CLIENT_ID)
+ gClientState->selfID = ipcMessageCast<ipcmMessageClientID>(msg)->ClientID();
+ else
+ {
+ LOG(("unexpected response from CLIENT_HELLO message: type=%x!\n",
+ IPCM_GetType(msg)));
+ rv = NS_ERROR_UNEXPECTED;
+ }
+
+ delete msg;
+ return rv;
+}
+
+nsresult
+IPC_Init()
+{
+ NS_ENSURE_TRUE(!gClientState, NS_ERROR_ALREADY_INITIALIZED);
+
+ IPC_InitLog(">>>");
+
+ gClientState = ipcClientState::Create();
+ if (!gClientState)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsresult rv = TryConnect();
+ if (NS_FAILED(rv))
+ IPC_Shutdown();
+
+ return rv;
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+EnumerateTargetMapAndNotify(const nsID &aKey,
+ ipcTargetData *aData,
+ void *aClosure);
+
+nsresult
+IPC_Shutdown()
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ LOG(("IPC_Shutdown: connected=%d\n",gClientState->connected));
+
+ if (gClientState->connected)
+ {
+ {
+ // first, set the shutdown flag and unblock any calls to WaitTarget.
+ // all targets but IPCM will not be able to use WaitTarget any more.
+
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ nsAutoMonitor mon(gClientState->monitor);
+#else
+ RTCritSectRwEnterExcl(&gClientState->critSect);
+#endif
+
+ gClientState->shutdown = PR_TRUE;
+ gClientState->targetMap.EnumerateRead(EnumerateTargetMapAndNotify, nsnull);
+
+#ifdef VBOX_WITH_IPCCLIENT_RW_CS
+ RTCritSectRwLeaveExcl(&gClientState->critSect);
+#endif
+ }
+
+ // inform all client observers that we're being shutdown to let interested
+ // parties gracefully uninitialize themselves. the IPCM target is still
+ // fully operational at this point, so they can use IPC_SendMessage
+ // (this is essential for the DConnect extension, for example, to do the
+ // proper uninitialization).
+
+ ipcEvent_ClientState *ev = new ipcEvent_ClientState(IPC_SENDER_ANY,
+ IPCM_CLIENT_STATE_DOWN);
+ ipcEvent_ClientState::HandleEvent (ev);
+ ipcEvent_ClientState::DestroyEvent (ev);
+
+ IPC_Disconnect();
+ }
+
+ //
+ // make gClientState nsnull before deletion to cause all public IPC_*
+ // calls (possibly made during ipcClientState destruction) to return
+ // NS_ERROR_NOT_INITIALIZED.
+ //
+ // NOTE: isn't just checking for gClientState->connected in every appropriate
+ // IPC_* method a better solution?
+ //
+ ipcClientState *aClientState = gClientState;
+ gClientState = nsnull;
+ delete aClientState;
+
+ return NS_OK;
+}
+
+/* ------------------------------------------------------------------------- */
+
+nsresult
+IPC_DefineTarget(const nsID &aTarget,
+ ipcIMessageObserver *aObserver,
+ PRBool aOnCurrentThread)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ // do not permit the re-definition of the IPCM protocol's target.
+ if (aTarget.Equals(IPCM_TARGET))
+ return NS_ERROR_INVALID_ARG;
+
+ nsresult rv;
+
+ nsRefPtr<ipcTargetData> td;
+ if (GetTarget(aTarget, getter_AddRefs(td)))
+ {
+ // clear out observer before removing target since we want to ensure that
+ // the observer is released on the main thread.
+ {
+ nsAutoMonitor mon(td->monitor);
+ td->SetObserver(aObserver, aOnCurrentThread);
+ }
+
+ // remove target outside of td's monitor to avoid holding the monitor
+ // while entering the client state's monitor.
+ if (!aObserver)
+ RemoveTarget(aTarget, PR_TRUE);
+
+ rv = NS_OK;
+ }
+ else
+ {
+ if (aObserver)
+ rv = DefineTarget(aTarget, aObserver, aOnCurrentThread, PR_TRUE, nsnull);
+ else
+ rv = NS_ERROR_INVALID_ARG; // unknown target
+ }
+
+ return rv;
+}
+
+nsresult
+IPC_DisableMessageObserver(const nsID &aTarget)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ // do not permit modifications to the IPCM protocol's target.
+ if (aTarget.Equals(IPCM_TARGET))
+ return NS_ERROR_INVALID_ARG;
+
+ DisableMessageObserver(aTarget);
+ return NS_OK;
+}
+
+nsresult
+IPC_EnableMessageObserver(const nsID &aTarget)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ // do not permit modifications to the IPCM protocol's target.
+ if (aTarget.Equals(IPCM_TARGET))
+ return NS_ERROR_INVALID_ARG;
+
+ EnableMessageObserver(aTarget);
+ return NS_OK;
+}
+
+nsresult
+IPC_SendMessage(PRUint32 aReceiverID,
+ const nsID &aTarget,
+ const PRUint8 *aData,
+ PRUint32 aDataLen)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ // do not permit sending IPCM messages
+ if (aTarget.Equals(IPCM_TARGET))
+ return NS_ERROR_INVALID_ARG;
+
+ nsresult rv;
+ if (aReceiverID == 0)
+ {
+ ipcMessage *msg = new ipcMessage(aTarget, (const char *) aData, aDataLen);
+ if (!msg)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ rv = IPC_SendMsg(msg);
+ }
+ else
+ rv = MakeIPCMRequest(new ipcmMessageForward(IPCM_MSG_REQ_FORWARD,
+ aReceiverID,
+ aTarget,
+ (const char *) aData,
+ aDataLen));
+
+ return rv;
+}
+
+struct WaitMessageSelectorData
+{
+ PRUint32 senderID;
+ ipcIMessageObserver *observer;
+ PRBool senderDead;
+};
+
+static nsresult WaitMessageSelector(void *arg, ipcTargetData *td, const ipcMessage *msg)
+{
+ WaitMessageSelectorData *data = (WaitMessageSelectorData *) arg;
+#ifdef VBOX
+ if (!msg)
+ {
+ /* Special NULL message which asks to check whether the client is
+ * still alive. Called when there is nothing suitable in the queue. */
+ ipcIMessageObserver *obs = data->observer;
+ if (!obs)
+ obs = td->observer;
+ NS_ASSERTION(obs, "must at least have a default observer");
+
+ nsresult rv = obs->OnMessageAvailable(IPC_SENDER_ANY, nsID(), 0, 0);
+ if (rv != IPC_WAIT_NEXT_MESSAGE)
+ data->senderDead = PR_TRUE;
+
+ return rv;
+ }
+#endif /* VBOX */
+
+ // process the specially forwarded client state message to see if the
+ // sender we're waiting a message from has died.
+
+ if (msg->Target().Equals(IPCM_TARGET))
+ {
+ switch (IPCM_GetType(msg))
+ {
+ case IPCM_MSG_PSH_CLIENT_STATE:
+ {
+ ipcMessageCast<ipcmMessageClientState> status(msg);
+ if ((data->senderID == IPC_SENDER_ANY ||
+ status->ClientID() == data->senderID) &&
+ status->ClientState() == IPCM_CLIENT_STATE_DOWN)
+ {
+ LOG(("sender (%d) we're waiting a message from (%d) has died\n",
+ status->ClientID(), data->senderID));
+
+ if (data->senderID != IPC_SENDER_ANY)
+ {
+ // we're waiting on a particular client, so IPC_WaitMessage must
+ // definitely fail with the NS_ERROR_xxx result.
+
+ data->senderDead = PR_TRUE;
+ return IPC_DISCARD_MESSAGE; // consume the message
+ }
+ else
+ {
+ // otherwise inform the observer about the client death using a special
+ // null message with an empty target id, and fail IPC_WaitMessage call
+ // with NS_ERROR_xxx only if the observer accepts this message.
+
+ ipcIMessageObserver *obs = data->observer;
+ if (!obs)
+ obs = td->observer;
+ NS_ASSERTION(obs, "must at least have a default observer");
+
+ nsresult rv = obs->OnMessageAvailable(status->ClientID(), nsID(), 0, 0);
+ if (rv != IPC_WAIT_NEXT_MESSAGE)
+ data->senderDead = PR_TRUE;
+
+ return IPC_DISCARD_MESSAGE; // consume the message
+ }
+ }
+#ifdef VBOX
+ else if ((data->senderID == IPC_SENDER_ANY ||
+ status->ClientID() == data->senderID) &&
+ status->ClientState() == IPCM_CLIENT_STATE_UP)
+ {
+ LOG(("sender (%d) we're waiting a message from (%d) has come up\n",
+ status->ClientID(), data->senderID));
+ if (data->senderID == IPC_SENDER_ANY)
+ {
+ // inform the observer about the client appearance using a special
+ // null message with an empty target id, but a length of 1.
+
+ ipcIMessageObserver *obs = data->observer;
+ if (!obs)
+ obs = td->observer;
+ NS_ASSERTION(obs, "must at least have a default observer");
+
+ nsresult rv = obs->OnMessageAvailable(status->ClientID(), nsID(), 0, 1);
+ /* VBoxSVC/VBoxXPCOMIPCD auto-start can cause that a client up
+ * message arrives while we're already waiting for a response
+ * from this client. Don't declare the connection as dead in
+ * this case. A client ID wraparound can't falsely trigger
+ * this, since the waiting thread would have hit the liveness
+ * check in the mean time. We MUST consume the message, otherwise
+ * IPCM messages pile up as long as there is a pending call, which
+ * can lead to severe processing overhead. */
+ return IPC_DISCARD_MESSAGE; // consume the message
+ }
+ }
+#endif /* VBOX */
+ break;
+ }
+ default:
+ NS_NOTREACHED("unexpected message");
+ }
+ return IPC_WAIT_NEXT_MESSAGE; // continue iterating
+ }
+
+ nsresult rv = IPC_WAIT_NEXT_MESSAGE;
+
+ if (data->senderID == IPC_SENDER_ANY ||
+ msg->mMetaData == data->senderID)
+ {
+ ipcIMessageObserver *obs = data->observer;
+ if (!obs)
+ obs = td->observer;
+ NS_ASSERTION(obs, "must at least have a default observer");
+
+ rv = obs->OnMessageAvailable(msg->mMetaData,
+ msg->Target(),
+ (const PRUint8 *) msg->Data(),
+ msg->DataLen());
+ }
+
+ // stop iterating if we got a match that the observer accepted.
+ return rv != IPC_WAIT_NEXT_MESSAGE ? NS_OK : IPC_WAIT_NEXT_MESSAGE;
+}
+
+nsresult
+IPC_WaitMessage(PRUint32 aSenderID,
+ const nsID &aTarget,
+ ipcIMessageObserver *aObserver,
+ ipcIMessageObserver *aConsumer,
+ PRIntervalTime aTimeout)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ // do not permit waiting for IPCM messages
+ if (aTarget.Equals(IPCM_TARGET))
+ return NS_ERROR_INVALID_ARG;
+
+ // use aObserver as the message selector
+ WaitMessageSelectorData data = { aSenderID, aObserver, PR_FALSE };
+
+ ipcMessage *msg;
+ nsresult rv = WaitTarget(aTarget, aTimeout, &msg, WaitMessageSelector, &data);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // if the selector has accepted some message, then we pass it to aConsumer
+ // for safe processing. The IPC susbsystem is quite stable here (i.e. we're
+ // not inside any of the monitors, and the message has been already removed
+ // from the pending queue).
+ if (aObserver && aConsumer)
+ {
+ aConsumer->OnMessageAvailable(msg->mMetaData,
+ msg->Target(),
+ (const PRUint8 *) msg->Data(),
+ msg->DataLen());
+ }
+
+ delete msg;
+
+ // if the requested sender has died while waiting, return an error
+ if (data.senderDead)
+ return NS_ERROR_ABORT; // XXX better error code?
+
+ return NS_OK;
+}
+
+/* ------------------------------------------------------------------------- */
+
+nsresult
+IPC_GetID(PRUint32 *aClientID)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ *aClientID = gClientState->selfID;
+ return NS_OK;
+}
+
+nsresult
+IPC_AddName(const char *aName)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ return MakeIPCMRequest(new ipcmMessageClientAddName(aName));
+}
+
+nsresult
+IPC_RemoveName(const char *aName)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ return MakeIPCMRequest(new ipcmMessageClientDelName(aName));
+}
+
+/* ------------------------------------------------------------------------- */
+
+nsresult
+IPC_AddClientObserver(ipcIClientObserver *aObserver)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ return gClientState->clientObservers.AppendObject(aObserver)
+ ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+nsresult
+IPC_RemoveClientObserver(ipcIClientObserver *aObserver)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ for (PRInt32 i = 0; i < gClientState->clientObservers.Count(); ++i)
+ {
+ if (gClientState->clientObservers[i] == aObserver)
+ gClientState->clientObservers.RemoveObjectAt(i);
+ }
+
+ return NS_OK;
+}
+
+/* ------------------------------------------------------------------------- */
+
+// this function could be called on any thread
+nsresult
+IPC_ResolveClientName(const char *aName, PRUint32 *aClientID)
+{
+ NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);
+
+ ipcMessage *msg = NULL;
+
+ nsresult rv = MakeIPCMRequest(new ipcmMessageQueryClientByName(aName), &msg);
+ if (NS_FAILED(rv))
+ {
+#ifdef VBOX /* MakeIPCMRequest may return a failure (e.g. NS_ERROR_CALL_FAILED) and a response msg. */
+ if (msg)
+ delete msg;
+#endif
+ return rv;
+ }
+
+ if (IPCM_GetType(msg) == IPCM_MSG_ACK_CLIENT_ID)
+ *aClientID = ipcMessageCast<ipcmMessageClientID>(msg)->ClientID();
+ else
+ {
+ LOG(("unexpected IPCM response: type=%x\n", IPCM_GetType(msg)));
+ rv = NS_ERROR_UNEXPECTED;
+ }
+
+ delete msg;
+ return rv;
+}
+
+/* ------------------------------------------------------------------------- */
+
+nsresult
+IPC_ClientExists(PRUint32 aClientID, PRBool *aResult)
+{
+ // this is a bit of a hack. we forward a PING to the specified client.
+ // the assumption is that the forwarding will only succeed if the client
+ // exists, so we wait for the RESULT message corresponding to the FORWARD
+ // request. if that gives a successful status, then we know that the
+ // client exists.
+
+ ipcmMessagePing ping;
+
+ return MakeIPCMRequest(new ipcmMessageForward(IPCM_MSG_REQ_FORWARD,
+ aClientID,
+ IPCM_TARGET,
+ ping.Data(),
+ ping.DataLen()));
+}
+
+/* ------------------------------------------------------------------------- */
+
+nsresult
+IPC_SpawnDaemon(const char *path)
+{
+ PRFileDesc *readable = nsnull, *writable = nsnull;
+ PRProcessAttr *attr = nsnull;
+ nsresult rv = NS_ERROR_FAILURE;
+ PRFileDesc *devNull;
+ char *const argv[] = { (char *const) path, nsnull };
+ char c;
+
+ // setup an anonymous pipe that we can use to determine when the daemon
+ // process has started up. the daemon will write a char to the pipe, and
+ // when we read it, we'll know to proceed with trying to connect to the
+ // daemon.
+
+ if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
+ goto end;
+ PR_SetFDInheritable(writable, PR_TRUE);
+
+ attr = PR_NewProcessAttr();
+ if (!attr)
+ goto end;
+
+ if (PR_ProcessAttrSetInheritableFD(attr, writable, IPC_STARTUP_PIPE_NAME) != PR_SUCCESS)
+ goto end;
+
+ devNull = PR_Open("/dev/null", PR_RDWR, 0);
+ if (!devNull)
+ goto end;
+
+ PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, devNull);
+ PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, devNull);
+ PR_ProcessAttrSetStdioRedirect(attr, PR_StandardError, devNull);
+
+ if (PR_CreateProcessDetached(path, argv, nsnull, attr) != PR_SUCCESS)
+ goto end;
+
+ // Close /dev/null
+ PR_Close(devNull);
+ // close the child end of the pipe in order to get notification on unexpected
+ // child termination instead of being infinitely blocked in PR_Read().
+ PR_Close(writable);
+ writable = nsnull;
+
+ if ((PR_Read(readable, &c, 1) != 1) || (c != IPC_STARTUP_PIPE_MAGIC))
+ goto end;
+
+ rv = NS_OK;
+end:
+ if (readable)
+ PR_Close(readable);
+ if (writable)
+ PR_Close(writable);
+ if (attr)
+ PR_DestroyProcessAttr(attr);
+ return rv;
+}
+
+/* ------------------------------------------------------------------------- */
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+EnumerateTargetMapAndNotify(const nsID &aKey,
+ ipcTargetData *aData,
+ void *aClosure)
+{
+ nsAutoMonitor mon(aData->monitor);
+
+ // wake up anyone waiting on this target.
+ mon.NotifyAll();
+
+ return PL_DHASH_NEXT;
+}
+
+// called on a background thread
+void
+IPC_OnConnectionEnd(nsresult error)
+{
+ // now, go through the target map, and tickle each monitor. that should
+ // unblock any calls to WaitTarget.
+
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ nsAutoMonitor mon(gClientState->monitor);
+#else
+ RTCritSectRwEnterExcl(&gClientState->critSect);
+#endif
+
+ gClientState->connected = PR_FALSE;
+ gClientState->targetMap.EnumerateRead(EnumerateTargetMapAndNotify, nsnull);
+
+#ifdef VBOX_WITH_IPCCLIENT_RW_CS
+ RTCritSectRwLeaveExcl(&gClientState->critSect);
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+PlaceOnPendingQ(const nsID &target, ipcTargetData *td, ipcMessage *msg)
+{
+ nsAutoMonitor mon(td->monitor);
+
+ // we only want to dispatch a 'ProcessPendingQ' event if we have not
+ // already done so.
+ PRBool dispatchEvent = td->pendingQ.IsEmpty();
+
+ // put this message on our pending queue
+ td->pendingQ.Append(msg);
+
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ char *targetStr = target.ToString();
+ LOG(("placed message on pending queue for target %s and notifying all...\n", targetStr));
+ nsMemory::Free(targetStr);
+ }
+#endif
+
+ // wake up anyone waiting on this queue
+ mon.NotifyAll();
+
+ // proxy call to target's message procedure
+ if (dispatchEvent)
+ CallProcessPendingQ(target, td);
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+EnumerateTargetMapAndPlaceMsg(const nsID &aKey,
+ ipcTargetData *aData,
+ void *userArg)
+{
+ if (!aKey.Equals(IPCM_TARGET))
+ {
+ // place a message clone to a target's event queue
+ ipcMessage *msg = (ipcMessage *) userArg;
+ PlaceOnPendingQ(aKey, aData, msg->Clone());
+ }
+
+ return PL_DHASH_NEXT;
+}
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef IPC_LOGGING
+#include "prprf.h"
+#include <ctype.h>
+#endif
+
+// called on a background thread
+void
+IPC_OnMessageAvailable(ipcMessage *msg)
+{
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ char *targetStr = msg->Target().ToString();
+ LOG(("got message for target: %s\n", targetStr));
+ nsMemory::Free(targetStr);
+
+// IPC_LogBinary((const PRUint8 *) msg->Data(), msg->DataLen());
+ }
+#endif
+
+ if (msg->Target().Equals(IPCM_TARGET))
+ {
+ switch (IPCM_GetType(msg))
+ {
+ // if this is a forwarded message, then post the inner message instead.
+ case IPCM_MSG_PSH_FORWARD:
+ {
+ ipcMessageCast<ipcmMessageForward> fwd(msg);
+ ipcMessage *innerMsg = new ipcMessage(fwd->InnerTarget(),
+ fwd->InnerData(),
+ fwd->InnerDataLen());
+ // store the sender's client id in the meta-data field of the message.
+ innerMsg->mMetaData = fwd->ClientID();
+
+ delete msg;
+
+ // recurse so we can handle forwarded IPCM messages
+ IPC_OnMessageAvailable(innerMsg);
+ return;
+ }
+ case IPCM_MSG_PSH_CLIENT_STATE:
+ {
+ ipcMessageCast<ipcmMessageClientState> status(msg);
+ PostEventToMainThread(new ipcEvent_ClientState(status->ClientID(),
+ status->ClientState()));
+
+ // go through the target map, and place this message to every target's
+ // pending event queue. that unblocks all WaitTarget calls (on all
+ // targets) giving them an opportuninty to finish wait cycle because of
+ // the peer client death, when appropriate.
+#ifndef VBOX_WITH_IPCCLIENT_RW_CS
+ nsAutoMonitor mon(gClientState->monitor);
+#else
+ RTCritSectRwEnterShared(&gClientState->critSect);
+#endif
+
+ gClientState->targetMap.EnumerateRead(EnumerateTargetMapAndPlaceMsg, msg);
+
+#ifdef VBOX_WITH_IPCCLIENT_RW_CS
+ RTCritSectRwLeaveShared(&gClientState->critSect);
+#endif
+ delete msg;
+
+ return;
+ }
+ }
+ }
+
+ nsRefPtr<ipcTargetData> td;
+ if (GetTarget(msg->Target(), getter_AddRefs(td)))
+ {
+ // make copy of target since |msg| may end up pointing to free'd memory
+ // once we notify the monitor inside PlaceOnPendingQ().
+ const nsID target = msg->Target();
+
+ PlaceOnPendingQ(target, td, msg);
+ }
+ else
+ {
+ NS_WARNING("message target is undefined");
+#ifdef VBOX
+ delete msg;
+#endif
+ }
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in
new file mode 100644
index 00000000..ad1a66b7
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in
@@ -0,0 +1,52 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+EXPORTS = \
+ ipcModule.h \
+ ipcModuleUtil.h \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h
new file mode 100644
index 00000000..2f299f70
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h
@@ -0,0 +1,240 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcModule_h__
+#define ipcModule_h__
+
+#include "nsID.h"
+
+//
+// a client handle is used to efficiently reference a client instance object
+// used by the daemon to represent a connection with a particular client app.
+//
+// modules should treat it as an opaque type.
+//
+typedef class ipcClient *ipcClientHandle;
+
+//-----------------------------------------------------------------------------
+// interface implemented by the module:
+//-----------------------------------------------------------------------------
+
+//
+// the version of ipcModuleMethods data structure.
+//
+#define IPC_MODULE_METHODS_VERSION (1<<16) // 1.0
+
+//
+// each module defines the following structure:
+//
+struct ipcModuleMethods
+{
+ //
+ // this field holds the version of the data structure, which is always the
+ // value of IPC_MODULE_METHODS_VERSION against which the module was built.
+ //
+ PRUint32 version;
+
+ //
+ // called after this module is registered.
+ //
+ void (* init) (void);
+
+ //
+ // called when this module will no longer be accessed.
+ //
+ void (* shutdown) (void);
+
+ //
+ // called when a new message arrives for this module.
+ //
+ // params:
+ // client - an opaque "handle" to an object representing the client that
+ // sent the message. modules should not store the value of this
+ // beyond the duration fo this function call. (e.g., the handle
+ // may be invalid after this function call returns.) modules
+ // wishing to hold onto a reference to a "client" should store
+ // the client's ID (see IPC_GetClientID).
+ // target - message target
+ // data - message data
+ // dataLen - message data length
+ //
+ void (* handleMsg) (ipcClientHandle client,
+ const nsID &target,
+ const void *data,
+ PRUint32 dataLen);
+
+ //
+ // called when a new client connects to the IPC daemon.
+ //
+ void (* clientUp) (ipcClientHandle client);
+
+ //
+ // called when a client disconnects from the IPC daemon.
+ //
+ void (* clientDown) (ipcClientHandle client);
+};
+
+//-----------------------------------------------------------------------------
+// interface implemented by the daemon:
+//-----------------------------------------------------------------------------
+
+//
+// the version of ipcDaemonMethods data structure.
+//
+#define IPC_DAEMON_METHODS_VERSION (1<<16) // 1.0
+
+//
+// enumeration functions may return FALSE to stop enumeration.
+//
+typedef PRBool (* ipcClientEnumFunc) (void *closure, ipcClientHandle client, PRUint32 clientID);
+typedef PRBool (* ipcClientNameEnumFunc) (void *closure, ipcClientHandle client, const char *name);
+typedef PRBool (* ipcClientTargetEnumFunc) (void *closure, ipcClientHandle client, const nsID &target);
+
+//
+// the daemon provides the following structure:
+//
+struct ipcDaemonMethods
+{
+ PRUint32 version;
+
+ //
+ // called to send a message to another module.
+ //
+ // params:
+ // client - identifies the client from which this message originated.
+ // target - message target
+ // data - message data
+ // dataLen - message data length
+ //
+ // returns:
+ // PR_SUCCESS if message was dispatched.
+ // PR_FAILURE if message could not be dispatched (possibly because
+ // no module is registered for the given message target).
+ //
+ PRStatus (* dispatchMsg) (ipcClientHandle client,
+ const nsID &target,
+ const void *data,
+ PRUint32 dataLen);
+
+ //
+ // called to send a message to a particular client or to broadcast a
+ // message to all clients.
+ //
+ // params:
+ // client - if null, then broadcast message to all clients. otherwise,
+ // send message to the client specified.
+ // target - message target
+ // data - message data
+ // dataLen - message data length
+ //
+ // returns:
+ // PR_SUCCESS if message was sent (or queued up to be sent later).
+ // PR_FAILURE if message could not be sent (possibly because the client
+ // does not have a registered observer for the msg's target).
+ //
+ PRStatus (* sendMsg) (ipcClientHandle client,
+ const nsID &target,
+ const void *data,
+ PRUint32 dataLen);
+
+ //
+ // called to lookup a client handle given its client ID. each client has
+ // a unique ID.
+ //
+ ipcClientHandle (* getClientByID) (PRUint32 clientID);
+
+ //
+ // called to lookup a client by name or alias. names are not necessary
+ // unique to individual clients. this function returns the client first
+ // registered under the given name.
+ //
+ ipcClientHandle (* getClientByName) (const char *name);
+
+ //
+ // called to enumerate all clients.
+ //
+ void (* enumClients) (ipcClientEnumFunc func, void *closure);
+
+ //
+ // returns the client ID of the specified client.
+ //
+ PRUint32 (* getClientID) (ipcClientHandle client);
+
+ //
+ // functions for inspecting the names and targets defined for a particular
+ // client instance.
+ //
+ PRBool (* clientHasName) (ipcClientHandle client, const char *name);
+ PRBool (* clientHasTarget) (ipcClientHandle client, const nsID &target);
+ void (* enumClientNames) (ipcClientHandle client, ipcClientNameEnumFunc func, void *closure);
+ void (* enumClientTargets) (ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure);
+};
+
+//-----------------------------------------------------------------------------
+// interface exported by a DSO implementing one or more modules:
+//-----------------------------------------------------------------------------
+
+struct ipcModuleEntry
+{
+ //
+ // identifies the message target of this module.
+ //
+ nsID target;
+
+ //
+ // module methods
+ //
+ ipcModuleMethods *methods;
+};
+
+//-----------------------------------------------------------------------------
+
+#define IPC_EXPORT extern "C" NS_EXPORT
+
+//
+// IPC_EXPORT int IPC_GetModules(const ipcDaemonMethods *, const ipcModuleEntry **);
+//
+// params:
+// methods - the daemon's methods
+// entries - the module entries defined by the DSO
+//
+// returns:
+// length of the |entries| array.
+//
+typedef int (* ipcGetModulesFunc) (const ipcDaemonMethods *methods, const ipcModuleEntry **entries);
+
+#endif // !ipcModule_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h
new file mode 100644
index 00000000..0d1703a8
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h
@@ -0,0 +1,151 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcModuleUtil_h__
+#define ipcModuleUtil_h__
+
+#include "prlog.h"
+#include "ipcModule.h"
+
+extern const ipcDaemonMethods *gIPCDaemonMethods;
+
+//-----------------------------------------------------------------------------
+// inline wrapper functions
+//
+// these functions may only be called by a module that uses the
+// IPC_IMPL_GETMODULES macro.
+//-----------------------------------------------------------------------------
+
+inline PRStatus
+IPC_DispatchMsg(ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ return gIPCDaemonMethods->dispatchMsg(client, target, data, dataLen);
+}
+
+inline PRStatus
+IPC_SendMsg(ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ return gIPCDaemonMethods->sendMsg(client, target, data, dataLen);
+}
+
+inline ipcClientHandle
+IPC_GetClientByID(PRUint32 id)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ return gIPCDaemonMethods->getClientByID(id);
+}
+
+inline ipcClientHandle
+IPC_GetClientByName(const char *name)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ return gIPCDaemonMethods->getClientByName(name);
+}
+
+inline void
+IPC_EnumClients(ipcClientEnumFunc func, void *closure)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ gIPCDaemonMethods->enumClients(func, closure);
+}
+
+inline PRUint32
+IPC_GetClientID(ipcClientHandle client)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ return gIPCDaemonMethods->getClientID(client);
+}
+
+inline PRBool
+IPC_ClientHasName(ipcClientHandle client, const char *name)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ return gIPCDaemonMethods->clientHasName(client, name);
+}
+
+inline PRBool
+IPC_ClientHasTarget(ipcClientHandle client, const nsID &target)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ return gIPCDaemonMethods->clientHasTarget(client, target);
+}
+
+inline void
+IPC_EnumClientNames(ipcClientHandle client, ipcClientNameEnumFunc func, void *closure)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ gIPCDaemonMethods->enumClientNames(client, func, closure);
+}
+
+inline void
+IPC_EnumClientTargets(ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure)
+{
+ PR_ASSERT(gIPCDaemonMethods);
+ gIPCDaemonMethods->enumClientTargets(client, func, closure);
+}
+
+//-----------------------------------------------------------------------------
+// inline composite functions
+//-----------------------------------------------------------------------------
+
+inline PRStatus
+IPC_SendMsg(PRUint32 clientID, const nsID &target, const void *data, PRUint32 dataLen)
+{
+ ipcClient *client = IPC_GetClientByID(clientID);
+ if (!client)
+ return PR_FAILURE;
+ return IPC_SendMsg(client, target, data, dataLen);
+}
+
+//-----------------------------------------------------------------------------
+// module factory macros
+//-----------------------------------------------------------------------------
+
+#define IPC_IMPL_GETMODULES(_modName, _modEntries) \
+ const ipcDaemonMethods *gIPCDaemonMethods; \
+ IPC_EXPORT int \
+ IPC_GetModules(const ipcDaemonMethods *dmeths, \
+ const ipcModuleEntry **ents) { \
+ /* XXX do version checking */ \
+ gIPCDaemonMethods = dmeths; \
+ *ents = _modEntries; \
+ return sizeof(_modEntries) / sizeof(ipcModuleEntry); \
+ }
+
+#endif // !ipcModuleUtil_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore
new file mode 100644
index 00000000..8d974b7c
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+mozilla-ipcd
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in
new file mode 100644
index 00000000..e9ef6c38
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in
@@ -0,0 +1,88 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+
+# required for #include "nsID.h"
+REQUIRES = \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = \
+ ipcd.cpp \
+ ipcClient.cpp \
+ ipcModuleReg.cpp \
+ ipcCommandModule.cpp
+
+ifeq ($(OS_ARCH),WINNT)
+CPPSRCS += ipcdWin.cpp
+else
+ifeq ($(OS_ARCH),BeOS)
+CPPSRCS += ipcdStub.cpp
+else
+CPPSRCS += ipcdUnix.cpp
+endif
+endif
+
+PROGRAM = mozilla-ipcd$(BIN_SUFFIX)
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/../../shared/src \
+ $(NULL)
+
+include $(topsrcdir)/config/config.mk
+
+LIBS = \
+ $(DIST)/lib/$(LIB_PREFIX)ipcdshared_s.$(LIB_SUFFIX) \
+ $(EXTRA_DSO_LIBS) \
+ $(NSPR_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+# For fruncate
+ifeq ($(OS_ARCH),Linux)
+DEFINES += -D_BSD_SOURCE
+endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp
new file mode 100644
index 00000000..4f68d175
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp
@@ -0,0 +1,235 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcLog.h"
+#include "ipcClient.h"
+#include "ipcMessage.h"
+#include "ipcModuleReg.h"
+#include "ipcd.h"
+#include "ipcm.h"
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+#include "prio.h"
+#endif
+
+PRUint32 ipcClient::gLastID = 0;
+
+//
+// called to initialize this client context
+//
+// assumptions:
+// - object's memory has already been zero'd out.
+//
+void
+ipcClient::Init()
+{
+ mID = ++gLastID;
+
+ // every client must be able to handle IPCM messages.
+ mTargets.Append(IPCM_TARGET);
+
+ // although it is tempting to fire off the NotifyClientUp event at this
+ // time, we must wait until the client sends us a CLIENT_HELLO event.
+ // see ipcCommandModule::OnClientHello.
+}
+
+//
+// called when this client context is going away
+//
+void
+ipcClient::Finalize()
+{
+ IPC_NotifyClientDown(this);
+
+ mNames.DeleteAll();
+ mTargets.DeleteAll();
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+ mInMsg.Reset();
+ mOutMsgQ.DeleteAll();
+#endif
+}
+
+void
+ipcClient::AddName(const char *name)
+{
+ LOG(("adding client name: %s\n", name));
+
+ if (HasName(name))
+ return;
+
+ mNames.Append(name);
+}
+
+PRBool
+ipcClient::DelName(const char *name)
+{
+ LOG(("deleting client name: %s\n", name));
+
+ return mNames.FindAndDelete(name);
+}
+
+void
+ipcClient::AddTarget(const nsID &target)
+{
+ LOG(("adding client target\n"));
+
+ if (HasTarget(target))
+ return;
+
+ mTargets.Append(target);
+}
+
+PRBool
+ipcClient::DelTarget(const nsID &target)
+{
+ LOG(("deleting client target\n"));
+
+ //
+ // cannot remove the IPCM target
+ //
+ if (!target.Equals(IPCM_TARGET))
+ return mTargets.FindAndDelete(target);
+
+ return PR_FALSE;
+}
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+
+//
+// called to process a client socket
+//
+// params:
+// fd - the client socket
+// poll_flags - the state of the client socket
+//
+// return:
+// 0 - to end session with this client
+// PR_POLL_READ - to wait for the client socket to become readable
+// PR_POLL_WRITE - to wait for the client socket to become writable
+//
+int
+ipcClient::Process(PRFileDesc *fd, int inFlags)
+{
+ if (inFlags & (PR_POLL_ERR | PR_POLL_HUP |
+ PR_POLL_EXCEPT | PR_POLL_NVAL)) {
+ LOG(("client socket appears to have closed\n"));
+ return 0;
+ }
+
+ // expect to wait for more data
+ int outFlags = PR_POLL_READ;
+
+ if (inFlags & PR_POLL_READ) {
+ LOG(("client socket is now readable\n"));
+
+ char buf[1024]; // XXX make this larger?
+ PRInt32 n;
+
+ // find out how much data is available for reading...
+ // n = PR_Available(fd);
+
+ n = PR_Read(fd, buf, sizeof(buf));
+ if (n <= 0)
+ return 0; // cancel connection
+
+ const char *ptr = buf;
+ while (n) {
+ PRUint32 nread;
+ PRBool complete;
+
+ if (mInMsg.ReadFrom(ptr, PRUint32(n), &nread, &complete) == PR_FAILURE) {
+ LOG(("message appears to be malformed; dropping client connection\n"));
+ return 0;
+ }
+
+ if (complete) {
+ IPC_DispatchMsg(this, &mInMsg);
+ mInMsg.Reset();
+ }
+
+ n -= nread;
+ ptr += nread;
+ }
+ }
+
+ if (inFlags & PR_POLL_WRITE) {
+ LOG(("client socket is now writable\n"));
+
+ if (mOutMsgQ.First())
+ WriteMsgs(fd);
+ }
+
+ if (mOutMsgQ.First())
+ outFlags |= PR_POLL_WRITE;
+
+ return outFlags;
+}
+
+//
+// called to write out any messages from the outgoing queue.
+//
+int
+ipcClient::WriteMsgs(PRFileDesc *fd)
+{
+ while (mOutMsgQ.First()) {
+ const char *buf = (const char *) mOutMsgQ.First()->MsgBuf();
+ PRInt32 bufLen = (PRInt32) mOutMsgQ.First()->MsgLen();
+
+ if (mSendOffset) {
+ buf += mSendOffset;
+ bufLen -= mSendOffset;
+ }
+
+ PRInt32 nw = PR_Write(fd, buf, bufLen);
+ if (nw <= 0)
+ break;
+
+ LOG(("wrote %d bytes\n", nw));
+
+ if (nw == bufLen) {
+ mOutMsgQ.DeleteFirst();
+ mSendOffset = 0;
+ }
+ else
+ mSendOffset += nw;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h
new file mode 100644
index 00000000..12e479cf
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h
@@ -0,0 +1,144 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcClientUnix_h__
+#define ipcClientUnix_h__
+
+#include "prio.h"
+#include "ipcMessageQ.h"
+#include "ipcStringList.h"
+#include "ipcIDList.h"
+
+#ifdef XP_WIN
+#include <windows.h>
+#endif
+
+//-----------------------------------------------------------------------------
+// ipcClient
+//
+// NOTE: this class is an implementation detail of the IPC daemon. IPC daemon
+// modules (other than the built-in IPCM module) must not access methods on
+// this class directly. use the API provided via ipcd.h instead.
+//-----------------------------------------------------------------------------
+
+class ipcClient
+{
+public:
+ void Init();
+ void Finalize();
+
+ PRUint32 ID() const { return mID; }
+
+ void AddName(const char *name);
+ PRBool DelName(const char *name);
+ PRBool HasName(const char *name) const { return mNames.Find(name) != NULL; }
+
+ void AddTarget(const nsID &target);
+ PRBool DelTarget(const nsID &target);
+ PRBool HasTarget(const nsID &target) const { return mTargets.Find(target) != NULL; }
+
+ // list iterators
+ const ipcStringNode *Names() const { return mNames.First(); }
+ const ipcIDNode *Targets() const { return mTargets.First(); }
+
+ // returns primary client name (the one specified in the "client hello" message)
+ const char *PrimaryName() const { return mNames.First() ? mNames.First()->Value() : NULL; }
+
+ void SetExpectsSyncReply(PRBool val) { mExpectsSyncReply = val; }
+ PRBool GetExpectsSyncReply() const { return mExpectsSyncReply; }
+
+#ifdef XP_WIN
+ PRUint32 PID() const { return mPID; }
+ void SetPID(PRUint32 pid) { mPID = pid; }
+
+ HWND Hwnd() const { return mHwnd; }
+ void SetHwnd(HWND hwnd) { mHwnd = hwnd; }
+#endif
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+ //
+ // called to process a client file descriptor. the value of pollFlags
+ // indicates the state of the socket.
+ //
+ // returns:
+ // 0 - to cancel client connection
+ // PR_POLL_READ - to poll for a readable socket
+ // PR_POLL_WRITE - to poll for a writable socket
+ // (both flags) - to poll for either a readable or writable socket
+ //
+ // the socket is non-blocking.
+ //
+ int Process(PRFileDesc *sockFD, int pollFlags);
+
+ //
+ // on success or failure, this function takes ownership of |msg| and will
+ // delete it when appropriate.
+ //
+ void EnqueueOutboundMsg(ipcMessage *msg) { mOutMsgQ.Append(msg); }
+#endif
+
+private:
+ static PRUint32 gLastID;
+
+ PRUint32 mID;
+ ipcStringList mNames;
+ ipcIDList mTargets;
+ PRBool mExpectsSyncReply;
+
+#ifdef XP_WIN
+ // on windows, we store the PID of the client process to help us determine
+ // the client from which a message originated. each message has the PID
+ // encoded in it.
+ PRUint32 mPID;
+
+ // the hwnd of the client's message window.
+ HWND mHwnd;
+#endif
+
+#if defined(XP_UNIX) || defined(XP_OS2)
+ ipcMessage mInMsg; // buffer for incoming message
+ ipcMessageQ mOutMsgQ; // outgoing message queue
+
+ // keep track of the amount of the first message sent
+ PRUint32 mSendOffset;
+
+ // utility function for writing out messages.
+ int WriteMsgs(PRFileDesc *fd);
+#endif
+};
+
+#endif // !ipcClientUnix_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp
new file mode 100644
index 00000000..43ac547c
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp
@@ -0,0 +1,316 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include <string.h>
+#include "ipcLog.h"
+#include "ipcCommandModule.h"
+#include "ipcModule.h"
+#include "ipcClient.h"
+#include "ipcMessage.h"
+#include "ipcMessageUtils.h"
+#include "ipcModuleReg.h"
+#include "ipcd.h"
+#include "ipcm.h"
+
+struct ipcCommandModule
+{
+ typedef void (* MsgHandler)(ipcClient *, const ipcMessage *);
+
+ //
+ // helpers
+ //
+
+ static char **
+ BuildStringArray(const ipcStringNode *nodes)
+ {
+ size_t count = 0;
+
+ const ipcStringNode *node;
+
+ for (node = nodes; node; node = node->mNext)
+ count++;
+
+ char **strs = (char **) malloc((count + 1) * sizeof(char *));
+ if (!strs)
+ return NULL;
+
+ count = 0;
+ for (node = nodes; node; node = node->mNext, ++count)
+ strs[count] = (char *) node->Value();
+ strs[count] = 0;
+
+ return strs;
+ }
+
+ static nsID **
+ BuildIDArray(const ipcIDNode *nodes)
+ {
+ size_t count = 0;
+
+ const ipcIDNode *node;
+
+ for (node = nodes; node; node = node->mNext)
+ count++;
+
+ nsID **ids = (nsID **) calloc(count + 1, sizeof(nsID *));
+ if (!ids)
+ return NULL;
+
+ count = 0;
+ for (node = nodes; node; node = node->mNext, ++count)
+ ids[count] = (nsID *) &node->Value();
+
+ return ids;
+ }
+
+ //
+ // message handlers
+ //
+
+ static void
+ OnPing(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got PING\n"));
+
+ IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK));
+ }
+
+ static void
+ OnClientHello(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got CLIENT_HELLO\n"));
+
+ IPC_SendMsg(client, new ipcmMessageClientID(IPCM_GetRequestIndex(rawMsg), client->ID()));
+
+ //
+ // NOTE: it would almost make sense for this notification to live
+ // in the transport layer code. however, clients expect to receive
+ // a CLIENT_ID as the first message following a CLIENT_HELLO, so we
+ // must not allow modules to see a client until after we have sent
+ // the CLIENT_ID message.
+ //
+ IPC_NotifyClientUp(client);
+ }
+
+ static void
+ OnClientAddName(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got CLIENT_ADD_NAME\n"));
+
+ PRInt32 status = IPCM_OK;
+ PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg);
+
+ ipcMessageCast<ipcmMessageClientAddName> msg(rawMsg);
+ const char *name = msg->Name();
+ if (name) {
+ ipcClient *result = IPC_GetClientByName(msg->Name());
+ if (result) {
+ LOG((" client with such name already exists (ID = %d)\n", result->ID()));
+ status = IPCM_ERROR_ALREADY_EXISTS;
+ }
+ else
+ client->AddName(name);
+ }
+ else
+ status = IPCM_ERROR_INVALID_ARG;
+
+ IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status));
+ }
+
+ static void
+ OnClientDelName(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got CLIENT_DEL_NAME\n"));
+
+ PRInt32 status = IPCM_OK;
+ PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg);
+
+ ipcMessageCast<ipcmMessageClientDelName> msg(rawMsg);
+ const char *name = msg->Name();
+ if (name) {
+ if (!client->DelName(name)) {
+ LOG((" client doesn't have name '%s'\n", name));
+ status = IPCM_ERROR_NO_SUCH_DATA;
+ }
+ }
+ else
+ status = IPCM_ERROR_INVALID_ARG;
+
+ IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status));
+ }
+
+ static void
+ OnClientAddTarget(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got CLIENT_ADD_TARGET\n"));
+
+ PRInt32 status = IPCM_OK;
+ PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg);
+
+ ipcMessageCast<ipcmMessageClientAddTarget> msg(rawMsg);
+ if (client->HasTarget(msg->Target())) {
+ LOG((" target already defined for client\n"));
+ status = IPCM_ERROR_ALREADY_EXISTS;
+ }
+ else
+ client->AddTarget(msg->Target());
+
+ IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status));
+ }
+
+ static void
+ OnClientDelTarget(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got CLIENT_DEL_TARGET\n"));
+
+ PRInt32 status = IPCM_OK;
+ PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg);
+
+ ipcMessageCast<ipcmMessageClientDelTarget> msg(rawMsg);
+ if (!client->DelTarget(msg->Target())) {
+ LOG((" client doesn't have the given target\n"));
+ status = IPCM_ERROR_NO_SUCH_DATA;
+ }
+
+ IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status));
+ }
+
+ static void
+ OnQueryClientByName(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got QUERY_CLIENT_BY_NAME\n"));
+
+ PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg);
+
+ ipcMessageCast<ipcmMessageQueryClientByName> msg(rawMsg);
+
+ ipcClient *result = IPC_GetClientByName(msg->Name());
+ if (result) {
+ LOG((" client exists w/ ID = %u\n", result->ID()));
+ IPC_SendMsg(client, new ipcmMessageClientID(requestIndex, result->ID()));
+ }
+ else {
+ LOG((" client does not exist\n"));
+ IPC_SendMsg(client, new ipcmMessageResult(requestIndex, IPCM_ERROR_NO_CLIENT));
+ }
+ }
+
+#if 0
+ static void
+ OnQueryClientInfo(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got QUERY_CLIENT_INFO\n"));
+
+ ipcMessageCast<ipcmMessageQueryClientInfo> msg(rawMsg);
+ ipcClient *result = IPC_GetClientByID(msg->ClientID());
+ if (result) {
+ char **names = BuildStringArray(result->Names());
+ nsID **targets = BuildIDArray(result->Targets());
+
+ IPC_SendMsg(client, new ipcmMessageClientInfo(result->ID(),
+ msg->RequestIndex(),
+ (const char **) names,
+ (const nsID **) targets));
+
+ free(names);
+ free(targets);
+ }
+ else {
+ LOG((" client does not exist\n"));
+ IPC_SendMsg(client, new ipcmMessageError(IPCM_ERROR_NO_CLIENT, msg->RequestIndex()));
+ }
+ }
+#endif
+
+ static void
+ OnForward(ipcClient *client, const ipcMessage *rawMsg)
+ {
+ LOG(("got FORWARD\n"));
+
+ ipcMessageCast<ipcmMessageForward> msg(rawMsg);
+
+ ipcClient *dest = IPC_GetClientByID(msg->ClientID());
+ if (!dest) {
+ LOG((" destination client not found!\n"));
+ IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_ERROR_NO_CLIENT));
+ return;
+ }
+ // inform client that its message will be forwarded
+ IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK));
+
+ ipcMessage *newMsg = new ipcmMessageForward(IPCM_MSG_PSH_FORWARD,
+ client->ID(),
+ msg->InnerTarget(),
+ msg->InnerData(),
+ msg->InnerDataLen());
+ IPC_SendMsg(dest, newMsg);
+ }
+};
+
+void
+IPCM_HandleMsg(ipcClient *client, const ipcMessage *rawMsg)
+{
+ static ipcCommandModule::MsgHandler handlers[] =
+ {
+ ipcCommandModule::OnPing,
+ ipcCommandModule::OnForward,
+ ipcCommandModule::OnClientHello,
+ ipcCommandModule::OnClientAddName,
+ ipcCommandModule::OnClientDelName,
+ ipcCommandModule::OnClientAddTarget,
+ ipcCommandModule::OnClientDelTarget,
+ ipcCommandModule::OnQueryClientByName
+ };
+
+ int type = IPCM_GetType(rawMsg);
+ LOG(("IPCM_HandleMsg [type=%x]\n", type));
+
+ if (!(type & IPCM_MSG_CLASS_REQ)) {
+ LOG(("not a request -- ignoring message\n"));
+ return;
+ }
+
+ type &= ~IPCM_MSG_CLASS_REQ;
+ type--;
+ if (type < 0 || type >= (int) (sizeof(handlers)/sizeof(handlers[0]))) {
+ LOG(("unknown request -- ignoring message\n"));
+ return;
+ }
+
+ (handlers[type])(client, rawMsg);
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h
new file mode 100644
index 00000000..ea146cdc
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h
@@ -0,0 +1,48 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcCommandModule_h__
+#define ipcCommandModule_h__
+
+#include "ipcm.h" // for IPCM_TARGET
+
+class ipcClient;
+class ipcMessage;
+
+void IPCM_HandleMsg(ipcClient *, const ipcMessage *);
+
+#endif // !ipcCommandModule_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp
new file mode 100644
index 00000000..09e60ab9
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp
@@ -0,0 +1,245 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "prlink.h"
+#include "prio.h"
+#include "prlog.h"
+#include "plstr.h"
+
+#include "ipcConfig.h"
+#include "ipcLog.h"
+#include "ipcModuleReg.h"
+#include "ipcModule.h"
+#include "ipcCommandModule.h"
+#include "ipcd.h"
+
+//-----------------------------------------------------------------------------
+
+struct ipcModuleRegEntry
+{
+ nsID target;
+ ipcModuleMethods *methods;
+ PRLibrary *lib;
+};
+
+#define IPC_MAX_MODULE_COUNT 64
+
+static ipcModuleRegEntry ipcModules[IPC_MAX_MODULE_COUNT];
+static int ipcModuleCount = 0;
+
+//-----------------------------------------------------------------------------
+
+static PRStatus
+AddModule(const nsID &target, ipcModuleMethods *methods, const char *libPath)
+{
+ if (ipcModuleCount == IPC_MAX_MODULE_COUNT) {
+ LOG(("too many modules!\n"));
+ return PR_FAILURE;
+ }
+
+ if (!methods) {
+ PR_NOT_REACHED("null module methods");
+ return PR_FAILURE;
+ }
+
+ //
+ // each ipcModuleRegEntry holds a reference to a PRLibrary, and on
+ // shutdown, each PRLibrary reference will be released. this ensures
+ // that the library will not be unloaded until all of the modules in
+ // that library are shutdown.
+ //
+ ipcModules[ipcModuleCount].target = target;
+ ipcModules[ipcModuleCount].methods = methods;
+ ipcModules[ipcModuleCount].lib = PR_LoadLibrary(libPath);
+
+ ++ipcModuleCount;
+ return PR_SUCCESS;
+}
+
+static void
+InitModuleFromLib(const char *modulesDir, const char *fileName)
+{
+ LOG(("InitModuleFromLib [%s]\n", fileName));
+
+ static const ipcDaemonMethods gDaemonMethods =
+ {
+ IPC_DAEMON_METHODS_VERSION,
+ IPC_DispatchMsg,
+ IPC_SendMsg,
+ IPC_GetClientByID,
+ IPC_GetClientByName,
+ IPC_EnumClients,
+ IPC_GetClientID,
+ IPC_ClientHasName,
+ IPC_ClientHasTarget,
+ IPC_EnumClientNames,
+ IPC_EnumClientTargets
+ };
+
+ int dLen = strlen(modulesDir);
+ int fLen = strlen(fileName);
+
+ char *buf = (char *) malloc(dLen + 1 + fLen + 1);
+ memcpy(buf, modulesDir, dLen);
+ buf[dLen] = IPC_PATH_SEP_CHAR;
+ memcpy(buf + dLen + 1, fileName, fLen);
+ buf[dLen + 1 + fLen] = '\0';
+
+ PRLibrary *lib = PR_LoadLibrary(buf);
+ if (lib) {
+ ipcGetModulesFunc func =
+ (ipcGetModulesFunc) PR_FindFunctionSymbol(lib, "IPC_GetModules");
+
+ LOG((" func=%p\n", (void*) func));
+
+ if (func) {
+ const ipcModuleEntry *entries = NULL;
+ int count = func(&gDaemonMethods, &entries);
+ for (int i=0; i<count; ++i) {
+ if (AddModule(entries[i].target, entries[i].methods, buf) == PR_SUCCESS) {
+ if (entries[i].methods->init)
+ entries[i].methods->init();
+ }
+ }
+ }
+ PR_UnloadLibrary(lib);
+ }
+
+ free(buf);
+}
+
+//-----------------------------------------------------------------------------
+// ipcModuleReg API
+//-----------------------------------------------------------------------------
+
+void
+IPC_InitModuleReg(const char *exePath)
+{
+ if (!(exePath && *exePath))
+ return;
+
+ //
+ // register plug-in modules
+ //
+ char *p = PL_strrchr(exePath, IPC_PATH_SEP_CHAR);
+ if (p == NULL) {
+ LOG(("unexpected exe path\n"));
+ return;
+ }
+
+ int baseLen = p - exePath;
+ int finalLen = baseLen + 1 + sizeof(IPC_MODULES_DIR);
+
+ // build full path to ipc modules
+ char *modulesDir = (char*) malloc(finalLen);
+ memcpy(modulesDir, exePath, baseLen);
+ modulesDir[baseLen] = IPC_PATH_SEP_CHAR;
+ memcpy(modulesDir + baseLen + 1, IPC_MODULES_DIR, sizeof(IPC_MODULES_DIR));
+
+ LOG(("loading libraries in %s\n", modulesDir));
+ //
+ // scan directory for IPC modules
+ //
+ PRDir *dir = PR_OpenDir(modulesDir);
+ if (dir) {
+ PRDirEntry *ent;
+ while ((ent = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
+ //
+ // locate extension, and check if dynamic library
+ //
+
+ const char *p = strrchr(ent->name, '.');
+ if (p && PL_strcasecmp(p, MOZ_DLL_SUFFIX) == 0)
+ InitModuleFromLib(modulesDir, ent->name);
+ }
+ PR_CloseDir(dir);
+ }
+
+ free(modulesDir);
+}
+
+void
+IPC_ShutdownModuleReg()
+{
+ //
+ // shutdown modules in reverse order
+ //
+ while (ipcModuleCount) {
+ ipcModuleRegEntry &entry = ipcModules[--ipcModuleCount];
+ if (entry.methods->shutdown)
+ entry.methods->shutdown();
+ if (entry.lib)
+ PR_UnloadLibrary(entry.lib);
+ }
+}
+
+void
+IPC_NotifyModulesClientUp(ipcClient *client)
+{
+ for (int i = 0; i < ipcModuleCount; ++i) {
+ ipcModuleRegEntry &entry = ipcModules[i];
+ if (entry.methods->clientUp)
+ entry.methods->clientUp(client);
+ }
+}
+
+void
+IPC_NotifyModulesClientDown(ipcClient *client)
+{
+ for (int i = 0; i < ipcModuleCount; ++i) {
+ ipcModuleRegEntry &entry = ipcModules[i];
+ if (entry.methods->clientDown)
+ entry.methods->clientDown(client);
+ }
+}
+
+PRStatus
+IPC_DispatchMsg(ipcClient *client, const nsID &target, const void *data, PRUint32 dataLen)
+{
+ // dispatch message to every module registered under the given target.
+ for (int i=0; i<ipcModuleCount; ++i) {
+ ipcModuleRegEntry &entry = ipcModules[i];
+ if (entry.target.Equals(target)) {
+ if (entry.methods->handleMsg)
+ entry.methods->handleMsg(client, target, data, dataLen);
+ }
+ }
+ return PR_SUCCESS;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h
new file mode 100644
index 00000000..d3fecd6c
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h
@@ -0,0 +1,70 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcModuleReg_h__
+#define ipcModuleReg_h__
+
+#include "ipcModule.h"
+
+//
+// called to init the module registry. this may only be called once at
+// startup or once after calling IPC_ShutdownModuleReg.
+//
+// params:
+// exePath - path to the daemon executable. modules are loaded from a
+// directory relative to the daemon executable.
+//
+void IPC_InitModuleReg(const char *exePath);
+
+//
+// called to shutdown the module registry. this may be called more than
+// once and need not follow a call to IPC_InitModuleReg.
+//
+void IPC_ShutdownModuleReg();
+
+//
+// returns the ipcModuleMethods for the given target.
+//
+ipcModuleMethods *IPC_GetModuleByTarget(const nsID &target);
+
+//
+// notifies all modules of client connect/disconnect
+//
+void IPC_NotifyModulesClientUp(ipcClient *);
+void IPC_NotifyModulesClientDown(ipcClient *);
+
+#endif // !ipcModuleReg_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp
new file mode 100644
index 00000000..60aca34a
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp
@@ -0,0 +1,235 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "prlog.h"
+#include "prio.h"
+
+#include "ipcConfig.h"
+#include "ipcLog.h"
+#include "ipcMessage.h"
+#include "ipcClient.h"
+#include "ipcModuleReg.h"
+#include "ipcModule.h"
+#include "ipcCommandModule.h"
+#include "ipcdPrivate.h"
+#include "ipcd.h"
+
+//-----------------------------------------------------------------------------
+
+void
+IPC_NotifyParent()
+{
+ PRFileDesc *fd = PR_GetInheritedFD(IPC_STARTUP_PIPE_NAME);
+ if (fd) {
+ char c = IPC_STARTUP_PIPE_MAGIC;
+ PR_Write(fd, &c, 1);
+ PR_Close(fd);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+PRStatus
+IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg)
+{
+ PR_ASSERT(client);
+ PR_ASSERT(msg);
+
+ // remember if client is expecting SYNC_REPLY. we'll add that flag to the
+ // next message sent to the client.
+ if (msg->TestFlag(IPC_MSG_FLAG_SYNC_QUERY)) {
+ PR_ASSERT(client->GetExpectsSyncReply() == PR_FALSE);
+ // XXX shouldn't we remember the TargetID as well, and only set the
+ // SYNC_REPLY flag on the next message sent to the same TargetID?
+ client->SetExpectsSyncReply(PR_TRUE);
+ }
+
+ if (msg->Target().Equals(IPCM_TARGET)) {
+ IPCM_HandleMsg(client, msg);
+ return PR_SUCCESS;
+ }
+
+ return IPC_DispatchMsg(client, msg->Target(), msg->Data(), msg->DataLen());
+}
+
+PRStatus
+IPC_SendMsg(ipcClient *client, ipcMessage *msg)
+{
+ PR_ASSERT(msg);
+
+ if (client == NULL) {
+ //
+ // broadcast
+ //
+ for (int i=0; i<ipcClientCount; ++i)
+ IPC_SendMsg(&ipcClients[i], msg->Clone());
+ delete msg;
+ return PR_SUCCESS;
+ }
+
+ // add SYNC_REPLY flag to message if client is expecting...
+ if (client->GetExpectsSyncReply()) {
+ msg->SetFlag(IPC_MSG_FLAG_SYNC_REPLY);
+ client->SetExpectsSyncReply(PR_FALSE);
+ }
+
+ if (client->HasTarget(msg->Target()))
+ return IPC_PlatformSendMsg(client, msg);
+
+ LOG((" no registered message handler\n"));
+ return PR_FAILURE;
+}
+
+void
+IPC_NotifyClientUp(ipcClient *client)
+{
+ LOG(("IPC_NotifyClientUp: clientID=%d\n", client->ID()));
+
+ // notify modules before other clients
+ IPC_NotifyModulesClientUp(client);
+
+ for (int i=0; i<ipcClientCount; ++i) {
+ if (&ipcClients[i] != client)
+ IPC_SendMsg(&ipcClients[i],
+ new ipcmMessageClientState(client->ID(), IPCM_CLIENT_STATE_UP));
+ }
+}
+
+void
+IPC_NotifyClientDown(ipcClient *client)
+{
+ LOG(("IPC_NotifyClientDown: clientID=%d\n", client->ID()));
+
+ // notify modules before other clients
+ IPC_NotifyModulesClientDown(client);
+
+ for (int i=0; i<ipcClientCount; ++i) {
+ if (&ipcClients[i] != client)
+ IPC_SendMsg(&ipcClients[i],
+ new ipcmMessageClientState(client->ID(), IPCM_CLIENT_STATE_DOWN));
+ }
+}
+
+//-----------------------------------------------------------------------------
+// IPC daemon methods
+//-----------------------------------------------------------------------------
+
+PRStatus
+IPC_SendMsg(ipcClient *client, const nsID &target, const void *data, PRUint32 dataLen)
+{
+ return IPC_SendMsg(client, new ipcMessage(target, (const char *) data, dataLen));
+}
+
+ipcClient *
+IPC_GetClientByID(PRUint32 clientID)
+{
+ // linear search OK since number of clients should be small
+ for (int i = 0; i < ipcClientCount; ++i) {
+ if (ipcClients[i].ID() == clientID)
+ return &ipcClients[i];
+ }
+ return NULL;
+}
+
+ipcClient *
+IPC_GetClientByName(const char *name)
+{
+ // linear search OK since number of clients should be small
+ for (int i = 0; i < ipcClientCount; ++i) {
+ if (ipcClients[i].HasName(name))
+ return &ipcClients[i];
+ }
+ return NULL;
+}
+
+void
+IPC_EnumClients(ipcClientEnumFunc func, void *closure)
+{
+ PR_ASSERT(func);
+ for (int i = 0; i < ipcClientCount; ++i) {
+ if (func(closure, &ipcClients[i], ipcClients[i].ID()) == PR_FALSE)
+ break;
+ }
+}
+
+PRUint32
+IPC_GetClientID(ipcClient *client)
+{
+ PR_ASSERT(client);
+ return client->ID();
+}
+
+PRBool
+IPC_ClientHasName(ipcClient *client, const char *name)
+{
+ PR_ASSERT(client);
+ PR_ASSERT(name);
+ return client->HasName(name);
+}
+
+PRBool
+IPC_ClientHasTarget(ipcClient *client, const nsID &target)
+{
+ PR_ASSERT(client);
+ return client->HasTarget(target);
+}
+
+void
+IPC_EnumClientNames(ipcClient *client, ipcClientNameEnumFunc func, void *closure)
+{
+ PR_ASSERT(client);
+ PR_ASSERT(func);
+ const ipcStringNode *node = client->Names();
+ while (node) {
+ if (func(closure, client, node->Value()) == PR_FALSE)
+ break;
+ node = node->mNext;
+ }
+}
+
+void
+IPC_EnumClientTargets(ipcClient *client, ipcClientTargetEnumFunc func, void *closure)
+{
+ PR_ASSERT(client);
+ PR_ASSERT(func);
+ const ipcIDNode *node = client->Targets();
+ while (node) {
+ if (func(closure, client, node->Value()) == PR_FALSE)
+ break;
+ node = node->mNext;
+ }
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h
new file mode 100644
index 00000000..5a0f2c2a
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h
@@ -0,0 +1,82 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef IPCD_H__
+#define IPCD_H__
+
+#include "ipcModule.h"
+#include "ipcMessage.h"
+
+//-----------------------------------------------------------------------------
+// IPC daemon methods (see struct ipcDaemonMethods)
+//
+// these functions may only be called directly from within the daemon. plug-in
+// modules must access these through the ipcDaemonMethods structure.
+//-----------------------------------------------------------------------------
+
+PRStatus IPC_DispatchMsg (ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen);
+PRStatus IPC_SendMsg (ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen);
+ipcClientHandle IPC_GetClientByID (PRUint32 id);
+ipcClientHandle IPC_GetClientByName (const char *name);
+void IPC_EnumClients (ipcClientEnumFunc func, void *closure);
+PRUint32 IPC_GetClientID (ipcClientHandle client);
+PRBool IPC_ClientHasName (ipcClientHandle client, const char *name);
+PRBool IPC_ClientHasTarget (ipcClientHandle client, const nsID &target);
+void IPC_EnumClientNames (ipcClientHandle client, ipcClientNameEnumFunc func, void *closure);
+void IPC_EnumClientTargets (ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure);
+
+//-----------------------------------------------------------------------------
+// other internal IPCD methods
+//-----------------------------------------------------------------------------
+
+//
+// dispatch message
+//
+PRStatus IPC_DispatchMsg(ipcClientHandle client, const ipcMessage *msg);
+
+//
+// send message, takes ownership of |msg|.
+//
+PRStatus IPC_SendMsg(ipcClientHandle client, ipcMessage *msg);
+
+//
+// dispatch notifications about client connects and disconnects
+//
+void IPC_NotifyClientUp(ipcClientHandle client);
+void IPC_NotifyClientDown(ipcClientHandle client);
+
+#endif // !IPCD_H__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h
new file mode 100644
index 00000000..023b3a03
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h
@@ -0,0 +1,65 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcdPrivate_h__
+#define ipcdPrivate_h__
+
+class ipcClient;
+
+//
+// upper limit on the number of active connections
+// XXX may want to make this more dynamic
+//
+#define IPC_MAX_CLIENTS 10000
+
+//
+// array of connected clients
+//
+extern ipcClient *ipcClients;
+extern int ipcClientCount;
+
+//
+// platform specific send message function, takes ownership of |msg|.
+//
+PRStatus IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg);
+
+//
+// notify parent that it can connect to the daemon.
+//
+void IPC_NotifyParent();
+
+#endif // !ipcdPrivate_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp
new file mode 100644
index 00000000..10618110
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp
@@ -0,0 +1,77 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by IBM Corporation are Copyright (C) 2003
+ * IBM Corporation. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcd.h"
+#include "ipcdPrivate.h"
+#include "ipcLog.h"
+
+#include "prerror.h"
+
+//-----------------------------------------------------------------------------
+// use this file as a template to add server-side IPC connectivity.
+//
+// NOTE: if your platform supports local domain TCP sockets, then you should
+// be able to make use of ipcConnectionUnix.cpp.
+//-----------------------------------------------------------------------------
+
+// these variables are declared in ipcdPrivate.h and must be initialized by
+// when the daemon starts up.
+ipcClient *ipcClients = NULL;
+int ipcClientCount = 0;
+
+PRStatus
+IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg)
+{
+ const char notimplemented[] = "IPC_PlatformSendMsg not implemented";
+ PR_SetErrorText(sizeof(notimplemented), notimplemented);
+ return PR_FAILURE;
+}
+
+int main(int argc, char **argv)
+{
+ IPC_InitLog("###");
+
+ LOG(("daemon started...\n"));
+
+ /*
+ IPC_InitModuleReg(argv[0]);
+ IPC_ShutdownModuleReg();
+ */
+
+ // let the parent process know that we are up-and-running
+ IPC_NotifyParent();
+ return 0;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp
new file mode 100644
index 00000000..026e9e52
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp
@@ -0,0 +1,600 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(VBOX) && !defined(XP_OS2)
+# include <sys/resource.h>
+# include <errno.h>
+#endif
+
+#ifdef VBOX
+# include <iprt/initterm.h>
+#endif
+
+#include "prio.h"
+#include "prerror.h"
+#include "prthread.h"
+#include "prinrval.h"
+#include "plstr.h"
+#include "prprf.h"
+
+#include "ipcConfig.h"
+#include "ipcLog.h"
+#include "ipcMessage.h"
+#include "ipcClient.h"
+#include "ipcModuleReg.h"
+#include "ipcdPrivate.h"
+#include "ipcd.h"
+
+#if 0
+static void
+IPC_Sleep(int seconds)
+{
+ while (seconds > 0) {
+ LOG(("\rsleeping for %d seconds...", seconds));
+ PR_Sleep(PR_SecondsToInterval(1));
+ --seconds;
+ }
+ LOG(("\ndone sleeping\n"));
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// ipc directory and locking...
+//-----------------------------------------------------------------------------
+
+//
+// advisory file locking is used to ensure that only one IPC daemon is active
+// and bound to the local domain socket at a time.
+//
+// XXX this code does not work on OS/2.
+//
+#if !defined(XP_OS2)
+#define IPC_USE_FILE_LOCK
+#endif
+
+#ifdef IPC_USE_FILE_LOCK
+
+enum Status
+{
+ EOk = 0,
+ ELockFileOpen = -1,
+ ELockFileLock = -2,
+ ELockFileOwner = -3,
+};
+
+static int ipcLockFD = 0;
+
+static Status AcquireDaemonLock(const char *baseDir)
+{
+ const char lockName[] = "lock";
+
+ int dirLen = strlen(baseDir);
+ int len = dirLen // baseDir
+ + 1 // "/"
+ + sizeof(lockName); // "lock"
+
+ char *lockFile = (char *) malloc(len);
+ memcpy(lockFile, baseDir, dirLen);
+ lockFile[dirLen] = '/';
+ memcpy(lockFile + dirLen + 1, lockName, sizeof(lockName));
+
+#ifdef VBOX
+ //
+ // Security checks for the directory
+ //
+ struct stat st;
+ if (stat(baseDir, &st) == -1)
+ {
+ printf("Cannot stat '%s'.\n", baseDir);
+ return ELockFileOwner;
+ }
+
+ if (st.st_uid != getuid() && st.st_uid != geteuid())
+ {
+ printf("Wrong owner (%d) of '%s'", st.st_uid, baseDir);
+ if ( !stat("/tmp", &st)
+ && (st.st_mode & 07777) != 01777)
+ printf(" -- check /tmp permissions (%o should be 1777)\n",
+ st.st_mode & 07777);
+ printf(".\n");
+ return ELockFileOwner;
+ }
+
+ if (st.st_mode != (S_IRUSR | S_IWUSR | S_IXUSR | S_IFDIR))
+ {
+ printf("Wrong mode (%o) of '%s'", st.st_mode, baseDir);
+ if ( !stat("/tmp", &st)
+ && (st.st_mode & 07777) != 01777)
+ printf(" -- check /tmp permissions (%o should be 1777)\n",
+ st.st_mode & 07777);
+ printf(".\n");
+ return ELockFileOwner;
+ }
+#endif
+
+ //
+ // open lock file. it remains open until we shutdown.
+ //
+ ipcLockFD = open(lockFile, O_WRONLY|O_CREAT, S_IWUSR|S_IRUSR);
+
+#ifndef VBOX
+ free(lockFile);
+#endif
+
+ if (ipcLockFD == -1)
+ return ELockFileOpen;
+
+#ifdef VBOX
+ //
+ // Security checks for the lock file
+ //
+ if (fstat(ipcLockFD, &st) == -1)
+ {
+ printf("Cannot stat '%s'.\n", lockFile);
+ free(lockFile);
+ return ELockFileOwner;
+ }
+
+ if (st.st_uid != getuid() && st.st_uid != geteuid())
+ {
+ printf("Wrong owner (%d) of '%s'.\n", st.st_uid, lockFile);
+ free(lockFile);
+ return ELockFileOwner;
+ }
+
+ if (st.st_mode != (S_IRUSR | S_IWUSR | S_IFREG))
+ {
+ printf("Wrong mode (%o) of '%s'.\n", st.st_mode, lockFile);
+ free(lockFile);
+ return ELockFileOwner;
+ }
+
+ free(lockFile);
+#endif
+
+ //
+ // we use fcntl for locking. assumption: filesystem should be local.
+ // this API is nice because the lock will be automatically released
+ // when the process dies. it will also be released when the file
+ // descriptor is closed.
+ //
+ struct flock lock;
+ lock.l_type = F_WRLCK;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_whence = SEEK_SET;
+ if (fcntl(ipcLockFD, F_SETLK, &lock) == -1)
+ return ELockFileLock;
+
+ //
+ // truncate lock file once we have exclusive access to it.
+ //
+ ftruncate(ipcLockFD, 0);
+
+ //
+ // write our PID into the lock file (this just seems like a good idea...
+ // no real purpose otherwise).
+ //
+ char buf[32];
+ int nb = PR_snprintf(buf, sizeof(buf), "%u\n", (unsigned long) getpid());
+ write(ipcLockFD, buf, nb);
+
+ return EOk;
+}
+
+static Status InitDaemonDir(const char *socketPath)
+{
+ LOG(("InitDaemonDir [sock=%s]\n", socketPath));
+
+ char *baseDir = PL_strdup(socketPath);
+
+ //
+ // make sure IPC directory exists (XXX this should be recursive)
+ //
+ char *p = strrchr(baseDir, '/');
+ if (p)
+ p[0] = '\0';
+ mkdir(baseDir, 0700);
+
+ //
+ // if we can't acquire the daemon lock, then another daemon
+ // must be active, so bail.
+ //
+ Status status = AcquireDaemonLock(baseDir);
+
+ PL_strfree(baseDir);
+
+ if (status == EOk) {
+ // delete an existing socket to prevent bind from failing.
+ unlink(socketPath);
+ }
+ return status;
+}
+
+static void ShutdownDaemonDir()
+{
+ LOG(("ShutdownDaemonDir\n"));
+
+ // deleting directory and files underneath it allows another process
+ // to think it has exclusive access. better to just leave the hidden
+ // directory in /tmp and let the OS clean it up via the usual tmpdir
+ // cleanup cron job.
+
+ // this removes the advisory lock, allowing other processes to acquire it.
+ if (ipcLockFD) {
+ close(ipcLockFD);
+ ipcLockFD = 0;
+ }
+}
+
+#endif // IPC_USE_FILE_LOCK
+
+//-----------------------------------------------------------------------------
+// poll list
+//-----------------------------------------------------------------------------
+
+//
+// declared in ipcdPrivate.h
+//
+ipcClient *ipcClients = NULL;
+int ipcClientCount = 0;
+
+//
+// the first element of this array is always zero; this is done so that the
+// k'th element of ipcClientArray corresponds to the k'th element of
+// ipcPollList.
+//
+static ipcClient ipcClientArray[IPC_MAX_CLIENTS + 1];
+
+//
+// element 0 contains the "server socket"
+//
+static PRPollDesc ipcPollList[IPC_MAX_CLIENTS + 1];
+
+//-----------------------------------------------------------------------------
+
+static int AddClient(PRFileDesc *fd)
+{
+ if (ipcClientCount == IPC_MAX_CLIENTS) {
+ LOG(("reached maximum client limit\n"));
+ return -1;
+ }
+
+ int pollCount = ipcClientCount + 1;
+
+ ipcClientArray[pollCount].Init();
+
+ ipcPollList[pollCount].fd = fd;
+ ipcPollList[pollCount].in_flags = PR_POLL_READ;
+ ipcPollList[pollCount].out_flags = 0;
+
+ ++ipcClientCount;
+ return 0;
+}
+
+static int RemoveClient(int clientIndex)
+{
+ PRPollDesc *pd = &ipcPollList[clientIndex];
+
+ PR_Close(pd->fd);
+
+ ipcClientArray[clientIndex].Finalize();
+
+ //
+ // keep the clients and poll_fds contiguous; move the last one into
+ // the spot held by the one that is going away.
+ //
+ int toIndex = clientIndex;
+ int fromIndex = ipcClientCount;
+ if (fromIndex != toIndex) {
+ memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient));
+ memcpy(&ipcPollList[toIndex], &ipcPollList[fromIndex], sizeof(PRPollDesc));
+ }
+
+ //
+ // zero out the old entries.
+ //
+ memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient));
+ memset(&ipcPollList[fromIndex], 0, sizeof(PRPollDesc));
+
+ --ipcClientCount;
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+static void PollLoop(PRFileDesc *listenFD)
+{
+ // the first element of ipcClientArray is unused.
+ memset(ipcClientArray, 0, sizeof(ipcClientArray));
+ ipcClients = ipcClientArray + 1;
+ ipcClientCount = 0;
+
+ ipcPollList[0].fd = listenFD;
+ ipcPollList[0].in_flags = PR_POLL_EXCEPT | PR_POLL_READ;
+
+ while (1) {
+ PRInt32 rv;
+ PRIntn i;
+
+ int pollCount = ipcClientCount + 1;
+
+ ipcPollList[0].out_flags = 0;
+
+ //
+ // poll
+ //
+ // timeout after 5 minutes. if no connections after timeout, then
+ // exit. this timeout ensures that we don't stay resident when no
+ // clients are interested in connecting after spawning the daemon.
+ //
+ // XXX add #define for timeout value
+ //
+ LOG(("calling PR_Poll [pollCount=%d]\n", pollCount));
+ rv = PR_Poll(ipcPollList, pollCount, PR_SecondsToInterval(60 * 5));
+ if (rv == -1) {
+ LOG(("PR_Poll failed [%d]\n", PR_GetError()));
+ return;
+ }
+
+ if (rv > 0) {
+ //
+ // process clients that are ready
+ //
+ for (i = 1; i < pollCount; ++i) {
+ if (ipcPollList[i].out_flags != 0) {
+ ipcPollList[i].in_flags =
+ ipcClientArray[i].Process(ipcPollList[i].fd,
+ ipcPollList[i].out_flags);
+ ipcPollList[i].out_flags = 0;
+ }
+ }
+
+ //
+ // cleanup any dead clients (indicated by a zero in_flags)
+ //
+ for (i = pollCount - 1; i >= 1; --i) {
+ if (ipcPollList[i].in_flags == 0)
+ RemoveClient(i);
+ }
+
+ //
+ // check for new connection
+ //
+ if (ipcPollList[0].out_flags & PR_POLL_READ) {
+ LOG(("got new connection\n"));
+
+ PRNetAddr clientAddr;
+ memset(&clientAddr, 0, sizeof(clientAddr));
+ PRFileDesc *clientFD;
+
+ // @todo : We need to handle errors from accept() especially something like
+ // EMFILE, which happens when we run out of file descriptors.
+ // and puts XPCOMIPCD in a poll/accept endless loop!
+ clientFD = PR_Accept(listenFD, &clientAddr, PR_INTERVAL_NO_WAIT);
+ if (clientFD == NULL) {
+ // ignore this error... perhaps the client disconnected.
+ LOG(("PR_Accept failed [%d]\n", PR_GetError()));
+ }
+ else {
+ // make socket non-blocking
+ PRSocketOptionData opt;
+ opt.option = PR_SockOpt_Nonblocking;
+ opt.value.non_blocking = PR_TRUE;
+ PR_SetSocketOption(clientFD, &opt);
+
+ if (AddClient(clientFD) != 0)
+ PR_Close(clientFD);
+ }
+ }
+ }
+
+ //
+ // shutdown if no clients
+ //
+ if (ipcClientCount == 0) {
+ LOG(("shutting down\n"));
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+PRStatus
+IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg)
+{
+ LOG(("IPC_PlatformSendMsg\n"));
+
+ //
+ // must copy message onto send queue.
+ //
+ client->EnqueueOutboundMsg(msg);
+
+ //
+ // since our Process method may have already been called, we must ensure
+ // that the PR_POLL_WRITE flag is set.
+ //
+ int clientIndex = client - ipcClientArray;
+ ipcPollList[clientIndex].in_flags |= PR_POLL_WRITE;
+
+ return PR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+
+int main(int argc, char **argv)
+{
+ PRFileDesc *listenFD = NULL;
+ PRNetAddr addr;
+
+#ifdef VBOX
+ /* Set up the runtime without loading the support driver. */
+ RTR3InitExe(argc, &argv, 0);
+#endif
+
+ //
+ // ignore SIGINT so <ctrl-c> from terminal only kills the client
+ // which spawned this daemon.
+ //
+ signal(SIGINT, SIG_IGN);
+ // XXX block others? check cartman
+
+ // ensure strict file permissions
+ umask(0077);
+
+ IPC_InitLog("###");
+
+ LOG(("daemon started...\n"));
+
+ //XXX uncomment these lines to test slow starting daemon
+ //IPC_Sleep(2);
+
+ // set socket address
+ addr.local.family = PR_AF_LOCAL;
+ if (argc < 2)
+ IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path));
+ else
+ PL_strncpyz(addr.local.path, argv[1], sizeof(addr.local.path));
+
+#ifdef IPC_USE_FILE_LOCK
+ Status status = InitDaemonDir(addr.local.path);
+ if (status != EOk) {
+ if (status == ELockFileLock) {
+ LOG(("Another daemon is already running, exiting.\n"));
+ // send a signal to the blocked parent to indicate success
+ IPC_NotifyParent();
+ return 0;
+ }
+ else {
+ LOG(("InitDaemonDir failed (status=%d)\n", status));
+ // don't notify the parent to cause it to fail in PR_Read() after
+ // we terminate
+#ifdef VBOX
+ if (status != ELockFileOwner)
+ printf("Cannot create a lock file for '%s'.\n"
+ "Check permissions.\n", addr.local.path);
+#endif
+ return 0;
+ }
+ }
+#endif
+
+ listenFD = PR_OpenTCPSocket(PR_AF_LOCAL);
+ if (!listenFD) {
+ LOG(("PR_OpenTCPSocket failed [%d]\n", PR_GetError()));
+ }
+ else if (PR_Bind(listenFD, &addr) != PR_SUCCESS) {
+ LOG(("PR_Bind failed [%d]\n", PR_GetError()));
+ }
+ else {
+ IPC_InitModuleReg(argv[0]);
+
+#ifdef VBOX
+ // Use large backlog, as otherwise local sockets can reject connection
+ // attempts. Usually harmless, but causes an unnecessary start attempt
+ // of IPCD (which will terminate straight away), and the next attempt
+ // usually succeeds. But better avoid unnecessary activities.
+ if (PR_Listen(listenFD, 128) != PR_SUCCESS) {
+#else /* !VBOX */
+ if (PR_Listen(listenFD, 5) != PR_SUCCESS) {
+#endif /* !VBOX */
+ LOG(("PR_Listen failed [%d]\n", PR_GetError()));
+ }
+ else {
+#ifndef VBOX
+ // redirect all standard file descriptors to /dev/null for
+ // proper daemonizing
+ PR_Close(PR_STDIN);
+ PR_Open("/dev/null", O_RDONLY, 0);
+ PR_Close(PR_STDOUT);
+ PR_Open("/dev/null", O_WRONLY, 0);
+ PR_Close(PR_STDERR);
+ PR_Open("/dev/null", O_WRONLY, 0);
+#endif
+
+ IPC_NotifyParent();
+
+#if defined(VBOX) && !defined(XP_OS2)
+ // Increase the file table size to 10240 or as high as possible.
+ struct rlimit lim;
+ if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
+ {
+ if ( lim.rlim_cur < 10240
+ && lim.rlim_cur < lim.rlim_max)
+ {
+ lim.rlim_cur = lim.rlim_max <= 10240 ? lim.rlim_max : 10240;
+ if (setrlimit(RLIMIT_NOFILE, &lim) == -1)
+ printf("WARNING: failed to increase file descriptor limit. (%d)\n", errno);
+ }
+ }
+ else
+ printf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno);
+#endif
+
+ PollLoop(listenFD);
+ }
+
+ IPC_ShutdownModuleReg();
+ }
+
+ //IPC_Sleep(5);
+
+#ifdef IPC_USE_FILE_LOCK
+ // it is critical that we release the lock before closing the socket,
+ // otherwise, a client might launch another daemon that would be unable
+ // to acquire the lock and would then leave the client without a daemon.
+
+ ShutdownDaemonDir();
+#endif
+
+ if (listenFD) {
+ LOG(("closing socket\n"));
+ PR_Close(listenFD);
+ }
+
+ return 0;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp
new file mode 100644
index 00000000..f89fba06
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp
@@ -0,0 +1,408 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <windows.h>
+
+#include "prthread.h"
+
+#include "ipcConfig.h"
+#include "ipcLog.h"
+#include "ipcMessage.h"
+#include "ipcClient.h"
+#include "ipcModuleReg.h"
+#include "ipcdPrivate.h"
+#include "ipcd.h"
+#include "ipcm.h"
+
+//
+// declared in ipcdPrivate.h
+//
+ipcClient *ipcClients = NULL;
+int ipcClientCount = 0;
+
+static ipcClient ipcClientArray[IPC_MAX_CLIENTS];
+
+static HWND ipcHwnd = NULL;
+static PRBool ipcShutdown = PR_FALSE;
+
+#define IPC_PURGE_TIMER_ID 1
+#define IPC_WM_SENDMSG (WM_USER + 1)
+#define IPC_WM_SHUTDOWN (WM_USER + 2)
+
+//-----------------------------------------------------------------------------
+// client array manipulation
+//-----------------------------------------------------------------------------
+
+static void
+RemoveClient(ipcClient *client)
+{
+ LOG(("RemoveClient\n"));
+
+ int clientIndex = client - ipcClientArray;
+
+ client->Finalize();
+
+ //
+ // move last ipcClient object down into the spot occupied by this client.
+ //
+ int fromIndex = ipcClientCount - 1;
+ int toIndex = clientIndex;
+ if (toIndex != fromIndex)
+ memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient));
+
+ memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient));
+
+ --ipcClientCount;
+ LOG((" num clients = %u\n", ipcClientCount));
+
+ if (ipcClientCount == 0) {
+ LOG((" shutting down...\n"));
+ KillTimer(ipcHwnd, IPC_PURGE_TIMER_ID);
+ PostQuitMessage(0);
+ ipcShutdown = PR_TRUE;
+ }
+}
+
+static void
+PurgeStaleClients()
+{
+ if (ipcClientCount == 0)
+ return;
+
+ LOG(("PurgeStaleClients [num-clients=%u]\n", ipcClientCount));
+ //
+ // walk the list of supposedly active clients, and verify the existance of
+ // their respective message windows.
+ //
+ char wName[IPC_CLIENT_WINDOW_NAME_MAXLEN];
+ for (int i=ipcClientCount-1; i>=0; --i) {
+ ipcClient *client = &ipcClientArray[i];
+
+ LOG((" checking client at index %u [client-id=%u pid=%u]\n",
+ i, client->ID(), client->PID()));
+
+ IPC_GetClientWindowName(client->PID(), wName);
+
+ // XXX dougt has ideas about how to make this better
+
+ HWND hwnd = FindWindow(IPC_CLIENT_WINDOW_CLASS, wName);
+ if (!hwnd) {
+ LOG((" client window not found; removing client!\n"));
+ RemoveClient(client);
+ }
+ }
+}
+
+static ipcClient *
+AddClient(HWND hwnd, PRUint32 pid)
+{
+ LOG(("AddClient\n"));
+
+ //
+ // before adding a new client, verify that all existing clients are
+ // still up and running. remove any stale clients.
+ //
+ PurgeStaleClients();
+
+ if (ipcClientCount == IPC_MAX_CLIENTS) {
+ LOG((" reached maximum client count!\n"));
+ return NULL;
+ }
+
+ ipcClient *client = &ipcClientArray[ipcClientCount];
+ client->Init();
+ client->SetHwnd(hwnd);
+ client->SetPID(pid); // XXX one function instead of 3
+
+ ++ipcClientCount;
+ LOG((" num clients = %u\n", ipcClientCount));
+
+ if (ipcClientCount == 1)
+ SetTimer(ipcHwnd, IPC_PURGE_TIMER_ID, 1000, NULL);
+
+ return client;
+}
+
+static ipcClient *
+GetClientByPID(PRUint32 pid)
+{
+ for (int i=0; i<ipcClientCount; ++i) {
+ if (ipcClientArray[i].PID() == pid)
+ return &ipcClientArray[i];
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// message processing
+//-----------------------------------------------------------------------------
+
+static void
+ProcessMsg(HWND hwnd, PRUint32 pid, const ipcMessage *msg)
+{
+ LOG(("ProcessMsg [pid=%u len=%u]\n", pid, msg->MsgLen()));
+
+ ipcClient *client = GetClientByPID(pid);
+
+ if (client) {
+ //
+ // if this is an IPCM "client hello" message, then reset the client
+ // instance object.
+ //
+ if (msg->Target().Equals(IPCM_TARGET) &&
+ IPCM_GetType(msg) == IPCM_MSG_REQ_CLIENT_HELLO) {
+ RemoveClient(client);
+ client = NULL;
+ }
+ }
+
+ if (client == NULL) {
+ client = AddClient(hwnd, pid);
+ if (!client)
+ return;
+ }
+
+ IPC_DispatchMsg(client, msg);
+}
+
+//-----------------------------------------------------------------------------
+
+PRStatus
+IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg)
+{
+ LOG(("IPC_PlatformSendMsg [clientID=%u clientPID=%u]\n",
+ client->ID(), client->PID()));
+
+ // use PostMessage to make this asynchronous; otherwise we might get
+ // some wierd SendMessage recursion between processes.
+
+ WPARAM wParam = (WPARAM) client->Hwnd();
+ LPARAM lParam = (LPARAM) msg;
+ if (!PostMessage(ipcHwnd, IPC_WM_SENDMSG, wParam, lParam)) {
+ LOG(("PostMessage failed\n"));
+ delete msg;
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// windows message loop
+//-----------------------------------------------------------------------------
+
+static LRESULT CALLBACK
+WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LOG(("got message [msg=%x wparam=%x lparam=%x]\n", uMsg, wParam, lParam));
+
+ if (uMsg == WM_COPYDATA) {
+ if (ipcShutdown) {
+ LOG(("ignoring message b/c daemon is shutting down\n"));
+ return TRUE;
+ }
+ COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam;
+ if (cd && cd->lpData) {
+ ipcMessage msg;
+ PRUint32 bytesRead;
+ PRBool complete;
+ // XXX avoid extra malloc
+ PRStatus rv = msg.ReadFrom((const char *) cd->lpData, cd->cbData,
+ &bytesRead, &complete);
+ if (rv == PR_SUCCESS && complete) {
+ //
+ // grab client PID and hwnd.
+ //
+ ProcessMsg((HWND) wParam, (PRUint32) cd->dwData, &msg);
+ }
+ else
+ LOG(("ignoring malformed message\n"));
+ }
+ return TRUE;
+ }
+
+ if (uMsg == IPC_WM_SENDMSG) {
+ HWND hWndDest = (HWND) wParam;
+ ipcMessage *msg = (ipcMessage *) lParam;
+
+ COPYDATASTRUCT cd;
+ cd.dwData = GetCurrentProcessId();
+ cd.cbData = (DWORD) msg->MsgLen();
+ cd.lpData = (PVOID) msg->MsgBuf();
+
+ LOG(("calling SendMessage...\n"));
+ SendMessage(hWndDest, WM_COPYDATA, (WPARAM) hWnd, (LPARAM) &cd);
+ LOG((" done.\n"));
+
+ delete msg;
+ return 0;
+ }
+
+ if (uMsg == WM_TIMER) {
+ PurgeStaleClients();
+ return 0;
+ }
+
+#if 0
+ if (uMsg == IPC_WM_SHUTDOWN) {
+ //
+ // since this message is handled asynchronously, it is possible
+ // that other clients may have come online since this was issued.
+ // in which case, we need to ignore this message.
+ //
+ if (ipcClientCount == 0) {
+ ipcShutdown = PR_TRUE;
+ PostQuitMessage(0);
+ }
+ return 0;
+ }
+#endif
+
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+//-----------------------------------------------------------------------------
+// daemon startup synchronization
+//-----------------------------------------------------------------------------
+
+static HANDLE ipcSyncEvent;
+
+static PRBool
+AcquireLock()
+{
+ ipcSyncEvent = CreateEvent(NULL, FALSE, FALSE,
+ IPC_SYNC_EVENT_NAME);
+ if (!ipcSyncEvent) {
+ LOG(("CreateEvent failed [%u]\n", GetLastError()));
+ return PR_FALSE;
+ }
+
+ // check to see if event already existed prior to this call.
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ LOG((" lock already set; exiting...\n"));
+ return PR_FALSE;
+ }
+
+ LOG((" acquired lock\n"));
+ return PR_TRUE;
+}
+
+static void
+ReleaseLock()
+{
+ if (ipcSyncEvent) {
+ LOG(("releasing lock...\n"));
+ CloseHandle(ipcSyncEvent);
+ ipcSyncEvent = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// main
+//-----------------------------------------------------------------------------
+
+#ifdef DEBUG
+int
+main()
+#else
+int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+#endif
+{
+ IPC_InitLog("###");
+
+ LOG(("daemon started...\n"));
+
+ if (!AcquireLock()) {
+ // unblock the parent; it should be able to find the IPC window of the
+ // other daemon process.
+ IPC_NotifyParent();
+ return 0;
+ }
+
+ // initialize global data
+ memset(ipcClientArray, 0, sizeof(ipcClientArray));
+ ipcClients = ipcClientArray;
+ ipcClientCount = 0;
+
+ // create message window up front...
+ WNDCLASS wc;
+ memset(&wc, 0, sizeof(wc));
+ wc.lpfnWndProc = WindowProc;
+ wc.lpszClassName = IPC_WINDOW_CLASS;
+
+ RegisterClass(&wc);
+
+ ipcHwnd = CreateWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME,
+ 0, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
+
+ // unblock the parent process; it should now look for the IPC window.
+ IPC_NotifyParent();
+
+ if (!ipcHwnd)
+ return -1;
+
+ // load modules relative to the location of the executable...
+ {
+ char path[MAX_PATH];
+ GetModuleFileName(NULL, path, sizeof(path));
+ IPC_InitModuleReg(path);
+ }
+
+ LOG(("entering message loop...\n"));
+ MSG msg;
+ while (GetMessage(&msg, ipcHwnd, 0, 0))
+ DispatchMessage(&msg);
+
+ // unload modules
+ IPC_ShutdownModuleReg();
+
+ //
+ // we release the daemon lock before destroying the window because the
+ // absence of our window is what will cause clients to try to spawn the
+ // daemon.
+ //
+ ReleaseLock();
+
+ //LOG(("sleeping 5 seconds...\n"));
+ //PR_Sleep(PR_SecondsToInterval(5));
+
+ LOG(("destroying message window...\n"));
+ DestroyWindow(ipcHwnd);
+ ipcHwnd = NULL;
+
+ LOG(("exiting\n"));
+ return 0;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in
new file mode 100644
index 00000000..e258946b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in
@@ -0,0 +1,49 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+DIRS = lock transmngr dconnect
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.kup
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.in
new file mode 100644
index 00000000..e6a89153
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.in
@@ -0,0 +1,52 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = public src
+
+ifdef ENABLE_TESTS
+DIRS += test
+endif
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.kup
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/Makefile.in
new file mode 100644
index 00000000..b2b3dbaa
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/Makefile.in
@@ -0,0 +1,53 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+XPIDL_MODULE= ipcd_dconnect
+
+XPIDLSRCS = \
+ ipcIDConnectService.idl \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl
new file mode 100644
index 00000000..6ca16a2d
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl
@@ -0,0 +1,79 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * This service provides methods similar to nsIComponentManager and
+ * nsIServiceManager. A ClientID parameter specifies the remote process
+ * in which the object should live.
+ *
+ * ipcIService can be used to determine the ClientID of a remote process.
+ *
+ * It is assumed that both processes have access to the same typelibs.
+ */
+[scriptable, uuid(fe07ed16-2710-4a1e-a4e2-81302b62bf0e)]
+interface ipcIDConnectService : nsISupports
+{
+ void createInstance(
+ in unsigned long aClientID,
+ in nsCIDRef aClass,
+ in nsIIDRef aIID,
+ [iid_is(aIID),retval] out nsQIResult result
+ );
+
+ void createInstanceByContractID(
+ in unsigned long aClientID,
+ in string aContractID,
+ in nsIIDRef aIID,
+ [iid_is(aIID),retval] out nsQIResult result
+ );
+
+ void getService(
+ in unsigned long aClientID,
+ in nsCIDRef aClass,
+ in nsIIDRef aIID,
+ [iid_is(aIID),retval] out nsQIResult result
+ );
+
+ void getServiceByContractID(
+ in unsigned long aClientID,
+ in string aContractID,
+ in nsIIDRef aIID,
+ [iid_is(aIID),retval] out nsQIResult result
+ );
+};
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.in
new file mode 100644
index 00000000..a9efaadf
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.in
@@ -0,0 +1,66 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+LIBRARY_NAME = ipcddconnect_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME = ipcd
+
+FORCE_USE_PIC = 1
+
+REQUIRES = \
+ xpcom \
+ string \
+ $(NULL)
+
+CPPSRCS = \
+ ipcDConnectService.cpp \
+ $(NULL)
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/../../../shared/src \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.kup
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp
new file mode 100644
index 00000000..32565df2
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp
@@ -0,0 +1,4210 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ * Dmitry A. Kuminov <dmik@innotek.de>
+ *
+ * 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 "ipcDConnectService.h"
+#include "ipcMessageWriter.h"
+#include "ipcMessageReader.h"
+#include "ipcLog.h"
+
+#include "nsIServiceManagerUtils.h"
+#include "nsIInterfaceInfo.h"
+#include "nsIInterfaceInfoManager.h"
+#include "nsIExceptionService.h"
+#include "nsString.h"
+#include "nsVoidArray.h"
+#include "nsCRT.h"
+#include "nsDeque.h"
+#include "xptcall.h"
+
+#ifdef VBOX
+# include <map>
+# include <list>
+# include <iprt/err.h>
+# include <iprt/req.h>
+# include <iprt/mem.h>
+# include <iprt/time.h>
+# include <iprt/thread.h>
+#endif /* VBOX */
+
+#if defined(DCONNECT_MULTITHREADED)
+
+#if !defined(DCONNECT_WITH_IPRT_REQ_POOL)
+#include "nsIThread.h"
+#include "nsIRunnable.h"
+#endif
+
+#if defined(DEBUG) && !defined(DCONNECT_STATS)
+#define DCONNECT_STATS
+#endif
+
+#if defined(DCONNECT_STATS)
+#include <stdio.h>
+#endif
+
+#endif
+
+// XXX TODO:
+// 1. add thread affinity field to SETUP messages
+
+//-----------------------------------------------------------------------------
+
+#define DCONNECT_IPC_TARGETID \
+{ /* 43ca47ef-ebc8-47a2-9679-a4703218089f */ \
+ 0x43ca47ef, \
+ 0xebc8, \
+ 0x47a2, \
+ {0x96, 0x79, 0xa4, 0x70, 0x32, 0x18, 0x08, 0x9f} \
+}
+static const nsID kDConnectTargetID = DCONNECT_IPC_TARGETID;
+
+//-----------------------------------------------------------------------------
+
+#define DCON_WAIT_TIMEOUT PR_INTERVAL_NO_TIMEOUT
+
+//-----------------------------------------------------------------------------
+
+//
+// +--------------------------------------+
+// | major opcode : 1 byte |
+// +--------------------------------------+
+// | minor opcode : 1 byte |
+// +--------------------------------------+
+// | flags : 2 bytes |
+// +--------------------------------------+
+// . .
+// . variable payload .
+// . .
+// +--------------------------------------+
+//
+
+// dconnect major opcodes
+#define DCON_OP_SETUP 1
+#define DCON_OP_RELEASE 2
+#define DCON_OP_INVOKE 3
+
+#define DCON_OP_SETUP_REPLY 4
+#define DCON_OP_INVOKE_REPLY 5
+
+// dconnect minor opcodes for DCON_OP_SETUP
+#define DCON_OP_SETUP_NEW_INST_CLASSID 1
+#define DCON_OP_SETUP_NEW_INST_CONTRACTID 2
+#define DCON_OP_SETUP_GET_SERV_CLASSID 3
+#define DCON_OP_SETUP_GET_SERV_CONTRACTID 4
+#define DCON_OP_SETUP_QUERY_INTERFACE 5
+
+// dconnect minor opcodes for RELEASE
+// dconnect minor opcodes for INVOKE
+
+// DCON_OP_SETUP_REPLY and DCON_OP_INVOKE_REPLY flags
+#define DCON_OP_FLAGS_REPLY_EXCEPTION 0x0001
+
+// Within this time all the worker threads must be terminated.
+#define VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS (5000)
+
+#pragma pack(1)
+
+struct DConnectOp
+{
+ PRUint8 opcode_major;
+ PRUint8 opcode_minor;
+ PRUint16 flags;
+ PRUint32 request_index; // initialized with NewRequestIndex
+};
+
+// SETUP structs
+
+struct DConnectSetup : DConnectOp
+{
+ nsID iid;
+};
+
+struct DConnectSetupClassID : DConnectSetup
+{
+ nsID classid;
+};
+
+struct DConnectSetupContractID : DConnectSetup
+{
+ char contractid[1]; // variable length
+};
+
+struct DConnectSetupQueryInterface : DConnectSetup
+{
+ DConAddr instance;
+};
+
+// SETUP_REPLY struct
+
+struct DConnectSetupReply : DConnectOp
+{
+ DConAddr instance;
+ nsresult status;
+ // optionally followed by a specially serialized nsIException instance (see
+ // ipcDConnectService::SerializeException) if DCON_OP_FLAGS_REPLY_EXCEPTION is
+ // present in flags
+};
+
+// RELEASE struct
+
+struct DConnectRelease : DConnectOp
+{
+ DConAddr instance;
+};
+
+// INVOKE struct
+
+struct DConnectInvoke : DConnectOp
+{
+ DConAddr instance;
+ PRUint16 method_index;
+ // followed by an array of in-param blobs
+};
+
+// INVOKE_REPLY struct
+
+struct DConnectInvokeReply : DConnectOp
+{
+ nsresult result;
+ // followed by an array of out-param blobs if NS_SUCCEEDED(result), and
+ // optionally by a specially serialized nsIException instance (see
+ // ipcDConnectService::SerializeException) if DCON_OP_FLAGS_REPLY_EXCEPTION is
+ // present in flags
+};
+
+#pragma pack()
+
+//-----------------------------------------------------------------------------
+
+struct DConAddrPlusPtr
+{
+ DConAddr addr;
+ void *p;
+};
+
+//-----------------------------------------------------------------------------
+
+ipcDConnectService *ipcDConnectService::mInstance = nsnull;
+
+//-----------------------------------------------------------------------------
+
+static nsresult
+SetupPeerInstance(PRUint32 aPeerID, DConnectSetup *aMsg, PRUint32 aMsgLen,
+ void **aInstancePtr);
+
+//-----------------------------------------------------------------------------
+
+// A wrapper class holding an instance to an in-process XPCOM object.
+
+class DConnectInstance
+{
+public:
+ DConnectInstance(PRUint32 peer, nsIInterfaceInfo *iinfo, nsISupports *instance)
+ : mPeer(peer)
+ , mIInfo(iinfo)
+ , mInstance(instance)
+ {}
+
+ nsISupports *RealInstance() { return mInstance; }
+ nsIInterfaceInfo *InterfaceInfo() { return mIInfo; }
+ PRUint32 Peer() { return mPeer; }
+
+ DConnectInstanceKey::Key GetKey() {
+ const nsID *iid;
+ mIInfo->GetIIDShared(&iid);
+ return DConnectInstanceKey::Key(mPeer, mInstance, iid);
+ }
+
+ NS_IMETHODIMP_(nsrefcnt) AddRef(void)
+ {
+ NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
+ nsrefcnt count;
+ count = PR_AtomicIncrement((PRInt32*)&mRefCnt);
+ return count;
+ }
+
+ NS_IMETHODIMP_(nsrefcnt) Release(void)
+ {
+ nsrefcnt count;
+ NS_PRECONDITION(0 != mRefCnt, "dup release");
+ count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
+ if (0 == count) {
+ NS_PRECONDITION(PRInt32(mRefCntIPC) == 0, "non-zero IPC refcnt");
+ mRefCnt = 1; /* stabilize */
+ delete this;
+ return 0;
+ }
+ return count;
+ }
+
+ // this gets called after calling AddRef() on an instance passed to the
+ // client over IPC in order to have a count of IPC client-related references
+ // separately from the overall reference count
+ NS_IMETHODIMP_(nsrefcnt) AddRefIPC(void)
+ {
+ NS_PRECONDITION(PRInt32(mRefCntIPC) >= 0, "illegal refcnt");
+ nsrefcnt count = PR_AtomicIncrement((PRInt32*)&mRefCntIPC);
+ return count;
+ }
+
+ // this gets called before calling Release() when DCON_OP_RELEASE is
+ // received from the IPC client and in other cases to balance AddRefIPC()
+ NS_IMETHODIMP_(nsrefcnt) ReleaseIPC(PRBool locked = PR_FALSE)
+ {
+ NS_PRECONDITION(0 != mRefCntIPC, "dup release");
+ nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCntIPC);
+ if (0 == count) {
+ // If the last IPC reference is released, remove this instance from the map.
+ // ipcDConnectService is guaranteed to still exist here
+ // (DConnectInstance lifetime is bound to ipcDConnectService)
+ nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+ if (dConnect)
+ dConnect->DeleteInstance(this, locked);
+ else
+ NS_NOTREACHED("ipcDConnectService has gone before DConnectInstance");
+ }
+ return count;
+ }
+
+private:
+ nsAutoRefCnt mRefCnt;
+ nsAutoRefCnt mRefCntIPC;
+ PRUint32 mPeer; // peer process "owning" this instance
+ nsCOMPtr<nsIInterfaceInfo> mIInfo;
+ nsCOMPtr<nsISupports> mInstance;
+};
+
+void
+ipcDConnectService::ReleaseWrappers(nsVoidArray &wrappers, PRUint32 peer)
+{
+ nsAutoLock lock (mLock);
+
+ for (PRInt32 i=0; i<wrappers.Count(); ++i)
+ {
+ DConnectInstance *wrapper = (DConnectInstance *)wrappers[i];
+ if (mInstanceSet.Contains(wrapper) && wrapper->Peer() == peer)
+ {
+ wrapper->ReleaseIPC(PR_TRUE /* locked */);
+ wrapper->Release();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+static nsresult
+SerializeParam(ipcMessageWriter &writer, const nsXPTType &t, const nsXPTCMiniVariant &v)
+{
+ switch (t.TagPart())
+ {
+ case nsXPTType::T_I8:
+ case nsXPTType::T_U8:
+ writer.PutInt8(v.val.u8);
+ break;
+
+ case nsXPTType::T_I16:
+ case nsXPTType::T_U16:
+ writer.PutInt16(v.val.u16);
+ break;
+
+ case nsXPTType::T_I32:
+ case nsXPTType::T_U32:
+ writer.PutInt32(v.val.u32);
+ break;
+
+ case nsXPTType::T_I64:
+ case nsXPTType::T_U64:
+ writer.PutBytes(&v.val.u64, sizeof(PRUint64));
+ break;
+
+ case nsXPTType::T_FLOAT:
+ writer.PutBytes(&v.val.f, sizeof(float));
+ break;
+
+ case nsXPTType::T_DOUBLE:
+ writer.PutBytes(&v.val.d, sizeof(double));
+ break;
+
+ case nsXPTType::T_BOOL:
+ writer.PutBytes(&v.val.b, sizeof(PRBool));
+ break;
+
+ case nsXPTType::T_CHAR:
+ writer.PutBytes(&v.val.c, sizeof(char));
+ break;
+
+ case nsXPTType::T_WCHAR:
+ writer.PutBytes(&v.val.wc, sizeof(PRUnichar));
+ break;
+
+ case nsXPTType::T_IID:
+ {
+ AssertReturn(v.val.p, NS_ERROR_INVALID_POINTER);
+ writer.PutBytes(v.val.p, sizeof(nsID));
+ }
+ break;
+
+ case nsXPTType::T_CHAR_STR:
+ {
+ if (v.val.p)
+ {
+ int len = strlen((const char *) v.val.p);
+ writer.PutInt32(len);
+ writer.PutBytes(v.val.p, len);
+ }
+ else
+ {
+ // put -1 to indicate null string
+ writer.PutInt32((PRUint32) -1);
+ }
+ }
+ break;
+
+ case nsXPTType::T_WCHAR_STR:
+ {
+ if (v.val.p)
+ {
+ int len = 2 * nsCRT::strlen((const PRUnichar *) v.val.p);
+ writer.PutInt32(len);
+ writer.PutBytes(v.val.p, len);
+ }
+ else
+ {
+ // put -1 to indicate null string
+ writer.PutInt32((PRUint32) -1);
+ }
+ }
+ break;
+
+ case nsXPTType::T_INTERFACE:
+ case nsXPTType::T_INTERFACE_IS:
+ NS_NOTREACHED("this should be handled elsewhere");
+ return NS_ERROR_UNEXPECTED;
+
+ case nsXPTType::T_ASTRING:
+ case nsXPTType::T_DOMSTRING:
+ {
+ const nsAString *str = (const nsAString *) v.val.p;
+
+ PRUint32 len = 2 * str->Length();
+ nsAString::const_iterator begin;
+ const PRUnichar *data = str->BeginReading(begin).get();
+
+ writer.PutInt32(len);
+ writer.PutBytes(data, len);
+ }
+ break;
+
+ case nsXPTType::T_UTF8STRING:
+ case nsXPTType::T_CSTRING:
+ {
+ const nsACString *str = (const nsACString *) v.val.p;
+
+ PRUint32 len = str->Length();
+ nsACString::const_iterator begin;
+ const char *data = str->BeginReading(begin).get();
+
+ writer.PutInt32(len);
+ writer.PutBytes(data, len);
+ }
+ break;
+
+ case nsXPTType::T_ARRAY:
+ // arrays are serialized after all other params outside this routine
+ break;
+
+ case nsXPTType::T_VOID:
+ case nsXPTType::T_PSTRING_SIZE_IS:
+ case nsXPTType::T_PWSTRING_SIZE_IS:
+ default:
+ LOG(("unexpected parameter type: %d\n", t.TagPart()));
+ return NS_ERROR_UNEXPECTED;
+ }
+ return NS_OK;
+}
+
+static nsresult
+DeserializeParam(ipcMessageReader &reader, const nsXPTType &t, nsXPTCVariant &v)
+{
+ // defaults
+ v.ptr = nsnull;
+ v.type = t;
+ v.flags = 0;
+
+ switch (t.TagPart())
+ {
+ case nsXPTType::T_I8:
+ case nsXPTType::T_U8:
+ v.val.u8 = reader.GetInt8();
+ break;
+
+ case nsXPTType::T_I16:
+ case nsXPTType::T_U16:
+ v.val.u16 = reader.GetInt16();
+ break;
+
+ case nsXPTType::T_I32:
+ case nsXPTType::T_U32:
+ v.val.u32 = reader.GetInt32();
+ break;
+
+ case nsXPTType::T_I64:
+ case nsXPTType::T_U64:
+ reader.GetBytes(&v.val.u64, sizeof(v.val.u64));
+ break;
+
+ case nsXPTType::T_FLOAT:
+ reader.GetBytes(&v.val.f, sizeof(v.val.f));
+ break;
+
+ case nsXPTType::T_DOUBLE:
+ reader.GetBytes(&v.val.d, sizeof(v.val.d));
+ break;
+
+ case nsXPTType::T_BOOL:
+ reader.GetBytes(&v.val.b, sizeof(v.val.b));
+ break;
+
+ case nsXPTType::T_CHAR:
+ reader.GetBytes(&v.val.c, sizeof(v.val.c));
+ break;
+
+ case nsXPTType::T_WCHAR:
+ reader.GetBytes(&v.val.wc, sizeof(v.val.wc));
+ break;
+
+ case nsXPTType::T_IID:
+ {
+ nsID *buf = (nsID *) nsMemory::Alloc(sizeof(nsID));
+ reader.GetBytes(buf, sizeof(nsID));
+ v.val.p = buf;
+ v.SetValIsAllocated();
+ }
+ break;
+
+ case nsXPTType::T_CHAR_STR:
+ {
+ PRUint32 len = reader.GetInt32();
+ if (len == (PRUint32) -1)
+ {
+ // it's a null string
+ v.val.p = nsnull;
+ }
+ else
+ {
+ char *buf = (char *) nsMemory::Alloc(len + 1);
+ reader.GetBytes(buf, len);
+ buf[len] = char(0);
+
+ v.val.p = buf;
+ v.SetValIsAllocated();
+ }
+ }
+ break;
+
+ case nsXPTType::T_WCHAR_STR:
+ {
+ PRUint32 len = reader.GetInt32();
+ if (len == (PRUint32) -1)
+ {
+ // it's a null string
+ v.val.p = nsnull;
+ }
+ else
+ {
+ PRUnichar *buf = (PRUnichar *) nsMemory::Alloc(len + 2);
+ reader.GetBytes(buf, len);
+ buf[len / 2] = PRUnichar(0);
+
+ v.val.p = buf;
+ v.SetValIsAllocated();
+ }
+ }
+ break;
+
+ case nsXPTType::T_INTERFACE:
+ case nsXPTType::T_INTERFACE_IS:
+ {
+ reader.GetBytes(&v.val.u64, sizeof(DConAddr));
+ // stub creation will be handled outside this routine. we only
+ // deserialize the DConAddr into v.val.u64 temporarily.
+ }
+ break;
+
+ case nsXPTType::T_ASTRING:
+ case nsXPTType::T_DOMSTRING:
+ {
+ PRUint32 len = reader.GetInt32();
+
+ nsString *str = new nsString();
+ str->SetLength(len / 2);
+ PRUnichar *buf = str->BeginWriting();
+ reader.GetBytes(buf, len);
+
+ v.val.p = str;
+ v.SetValIsDOMString();
+ }
+ break;
+
+ case nsXPTType::T_UTF8STRING:
+ case nsXPTType::T_CSTRING:
+ {
+ PRUint32 len = reader.GetInt32();
+
+ nsCString *str = new nsCString();
+ str->SetLength(len);
+ char *buf = str->BeginWriting();
+ reader.GetBytes(buf, len);
+
+ v.val.p = str;
+
+ // this distinction here is pretty pointless
+ if (t.TagPart() == nsXPTType::T_CSTRING)
+ v.SetValIsCString();
+ else
+ v.SetValIsUTF8String();
+ }
+ break;
+
+ case nsXPTType::T_ARRAY:
+ // arrays are deserialized after all other params outside this routine
+ break;
+
+ case nsXPTType::T_VOID:
+ case nsXPTType::T_PSTRING_SIZE_IS:
+ case nsXPTType::T_PWSTRING_SIZE_IS:
+ default:
+ LOG(("unexpected parameter type\n"));
+ return NS_ERROR_UNEXPECTED;
+ }
+ return NS_OK;
+}
+
+static nsresult
+SetupParam(const nsXPTParamInfo &p, nsXPTCVariant &v)
+{
+ const nsXPTType &t = p.GetType();
+
+ if (p.IsIn() && p.IsDipper())
+ {
+ v.ptr = nsnull;
+ v.flags = 0;
+
+ switch (t.TagPart())
+ {
+ case nsXPTType::T_ASTRING:
+ case nsXPTType::T_DOMSTRING:
+ v.val.p = new nsString();
+ if (!v.val.p)
+ return NS_ERROR_OUT_OF_MEMORY;
+ v.type = t;
+ v.SetValIsDOMString();
+ break;
+
+ case nsXPTType::T_UTF8STRING:
+ case nsXPTType::T_CSTRING:
+ v.val.p = new nsCString();
+ if (!v.val.p)
+ return NS_ERROR_OUT_OF_MEMORY;
+ v.type = t;
+ v.SetValIsCString();
+ break;
+
+ default:
+ LOG(("unhandled dipper: type=%d\n", t.TagPart()));
+ return NS_ERROR_UNEXPECTED;
+ }
+ }
+ else if (p.IsOut() || p.IsRetval())
+ {
+ memset(&v.val, 0, sizeof(v.val));
+ v.ptr = &v.val;
+ v.type = t;
+ v.flags = 0;
+ v.SetPtrIsData();
+
+ // the ownership of output nsID, string, wstring, interface pointers and
+ // arrays is transferred to the receiving party. Therefore, we need to
+ // instruct FinishParam() to perform a cleanup after serializing them.
+ switch (t.TagPart())
+ {
+ case nsXPTType::T_IID:
+ case nsXPTType::T_CHAR_STR:
+ case nsXPTType::T_WCHAR_STR:
+ case nsXPTType::T_ARRAY:
+ v.SetValIsAllocated();
+ break;
+ case nsXPTType::T_INTERFACE:
+ case nsXPTType::T_INTERFACE_IS:
+ v.SetValIsInterface();
+ break;
+ default:
+ break;
+ }
+ }
+
+ return NS_OK;
+}
+
+static void
+FinishParam(nsXPTCVariant &v)
+{
+#ifdef VBOX
+ /* make valgrind happy */
+ if (!v.MustFreeVal())
+ return;
+#endif
+ if (!v.val.p)
+ return;
+
+ if (v.IsValAllocated())
+ nsMemory::Free(v.val.p);
+ else if (v.IsValInterface())
+ ((nsISupports *) v.val.p)->Release();
+ else if (v.IsValDOMString())
+ delete (nsAString *) v.val.p;
+ else if (v.IsValUTF8String() || v.IsValCString())
+ delete (nsACString *) v.val.p;
+}
+
+static nsresult
+DeserializeResult(ipcMessageReader &reader, const nsXPTType &t, nsXPTCMiniVariant &v)
+{
+ if (v.val.p == nsnull)
+ return NS_OK;
+
+ switch (t.TagPart())
+ {
+ case nsXPTType::T_I8:
+ case nsXPTType::T_U8:
+ *((PRUint8 *) v.val.p) = reader.GetInt8();
+ break;
+
+ case nsXPTType::T_I16:
+ case nsXPTType::T_U16:
+ *((PRUint16 *) v.val.p) = reader.GetInt16();
+ break;
+
+ case nsXPTType::T_I32:
+ case nsXPTType::T_U32:
+ *((PRUint32 *) v.val.p) = reader.GetInt32();
+ break;
+
+ case nsXPTType::T_I64:
+ case nsXPTType::T_U64:
+ reader.GetBytes(v.val.p, sizeof(PRUint64));
+ break;
+
+ case nsXPTType::T_FLOAT:
+ reader.GetBytes(v.val.p, sizeof(float));
+ break;
+
+ case nsXPTType::T_DOUBLE:
+ reader.GetBytes(v.val.p, sizeof(double));
+ break;
+
+ case nsXPTType::T_BOOL:
+ reader.GetBytes(v.val.p, sizeof(PRBool));
+ break;
+
+ case nsXPTType::T_CHAR:
+ reader.GetBytes(v.val.p, sizeof(char));
+ break;
+
+ case nsXPTType::T_WCHAR:
+ reader.GetBytes(v.val.p, sizeof(PRUnichar));
+ break;
+
+ case nsXPTType::T_IID:
+ {
+ nsID *buf = (nsID *) nsMemory::Alloc(sizeof(nsID));
+ reader.GetBytes(buf, sizeof(nsID));
+ *((nsID **) v.val.p) = buf;
+ }
+ break;
+
+ case nsXPTType::T_CHAR_STR:
+ {
+ PRUint32 len = reader.GetInt32();
+ if (len == (PRUint32) -1)
+ {
+ // it's a null string
+#ifdef VBOX
+ *((char **) v.val.p) = NULL;
+#else
+ v.val.p = 0;
+#endif
+ }
+ else
+ {
+ char *buf = (char *) nsMemory::Alloc(len + 1);
+ reader.GetBytes(buf, len);
+ buf[len] = char(0);
+
+ *((char **) v.val.p) = buf;
+ }
+ }
+ break;
+
+ case nsXPTType::T_WCHAR_STR:
+ {
+ PRUint32 len = reader.GetInt32();
+ if (len == (PRUint32) -1)
+ {
+ // it's a null string
+#ifdef VBOX
+ *((PRUnichar **) v.val.p) = 0;
+#else
+ v.val.p = 0;
+#endif
+ }
+ else
+ {
+ PRUnichar *buf = (PRUnichar *) nsMemory::Alloc(len + 2);
+ reader.GetBytes(buf, len);
+ buf[len / 2] = PRUnichar(0);
+
+ *((PRUnichar **) v.val.p) = buf;
+ }
+ }
+ break;
+
+ case nsXPTType::T_INTERFACE:
+ case nsXPTType::T_INTERFACE_IS:
+ {
+ // stub creation will be handled outside this routine. we only
+ // deserialize the DConAddr and the original value of v.val.p
+ // into v.val.p temporarily. needs temporary memory alloc.
+ DConAddrPlusPtr *buf = (DConAddrPlusPtr *) nsMemory::Alloc(sizeof(DConAddrPlusPtr));
+ reader.GetBytes(&buf->addr, sizeof(DConAddr));
+ buf->p = v.val.p;
+ v.val.p = buf;
+ }
+ break;
+
+ case nsXPTType::T_ASTRING:
+ case nsXPTType::T_DOMSTRING:
+ {
+ PRUint32 len = reader.GetInt32();
+
+ nsAString *str = (nsAString *) v.val.p;
+
+ nsAString::iterator begin;
+ str->SetLength(len / 2);
+ str->BeginWriting(begin);
+
+ reader.GetBytes(begin.get(), len);
+ }
+ break;
+
+ case nsXPTType::T_UTF8STRING:
+ case nsXPTType::T_CSTRING:
+ {
+ PRUint32 len = reader.GetInt32();
+
+ nsACString *str = (nsACString *) v.val.p;
+
+ nsACString::iterator begin;
+ str->SetLength(len);
+ str->BeginWriting(begin);
+
+ reader.GetBytes(begin.get(), len);
+ }
+ break;
+
+ case nsXPTType::T_ARRAY:
+ // arrays are deserialized after all other params outside this routine
+ break;
+
+ case nsXPTType::T_VOID:
+ case nsXPTType::T_PSTRING_SIZE_IS:
+ case nsXPTType::T_PWSTRING_SIZE_IS:
+ default:
+ LOG(("unexpected parameter type\n"));
+ return NS_ERROR_UNEXPECTED;
+ }
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+//
+// Returns an element from the nsXPTCMiniVariant array by properly casting it to
+// nsXPTCVariant when requested
+#define GET_PARAM(params, isXPTCVariantArray, idx) \
+ (isXPTCVariantArray ? ((nsXPTCVariant *) params) [idx] : params [idx])
+
+// isResult is PR_TRUE if the size_is and length_is params are out or retval
+// so that nsXPTCMiniVariants contain pointers to their locations instead of the
+// values themselves.
+static nsresult
+GetArrayParamInfo(nsIInterfaceInfo *iinfo, uint16 methodIndex,
+ const nsXPTMethodInfo &methodInfo, nsXPTCMiniVariant *params,
+ PRBool isXPTCVariantArray, const nsXPTParamInfo &paramInfo,
+ PRBool isResult, PRUint32 &size, PRUint32 &length,
+ nsXPTType &elemType)
+{
+ // XXX multidimensional arrays are not supported so dimension is always 0 for
+ // getting the size_is argument number of the array itself and 1 for getting
+ // the type of elements stored in the array.
+
+ nsresult rv;
+
+ // get the array size
+ PRUint8 sizeArg;
+ rv = iinfo->GetSizeIsArgNumberForParam(methodIndex, &paramInfo, 0, &sizeArg);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // get the number of valid elements
+ PRUint8 lenArg;
+ rv = iinfo->GetLengthIsArgNumberForParam(methodIndex, &paramInfo, 0, &lenArg);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // according to XPT specs
+ // (http://www.mozilla.org/scriptable/typelib_file.html), size_is and
+ // length_is for arrays is always uint32. Check this too.
+ {
+ nsXPTParamInfo pi = methodInfo.GetParam (sizeArg);
+ if (pi.GetType().TagPart() != nsXPTType::T_U32)
+ {
+ LOG(("unexpected size_is() parameter type: $d\n",
+ pi.GetType().TagPart()));
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ pi = methodInfo.GetParam (lenArg);
+ if (pi.GetType().TagPart() != nsXPTType::T_U32)
+ {
+ LOG(("unexpected length_is() parameter type: $d\n",
+ pi.GetType().TagPart()));
+ return NS_ERROR_UNEXPECTED;
+ }
+ }
+
+ if (isResult)
+ {
+ length = *((PRUint32 *) GET_PARAM(params,isXPTCVariantArray, lenArg).val.p);
+ size = *((PRUint32 *) GET_PARAM(params, isXPTCVariantArray, sizeArg).val.p);
+ }
+ else
+ {
+ length = GET_PARAM(params, isXPTCVariantArray, lenArg).val.u32;
+ size = GET_PARAM(params, isXPTCVariantArray, sizeArg).val.u32;
+ }
+
+ if (length > size)
+ {
+ NS_WARNING("length_is() value is greater than size_is() value");
+ length = size;
+ }
+
+ // get type of array elements
+ rv = iinfo->GetTypeForParam(methodIndex, &paramInfo, 1, &elemType);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (elemType.IsArithmetic() &&
+ (elemType.IsPointer() || elemType.IsUniquePointer() ||
+ elemType.IsReference()))
+ {
+ LOG(("arrays of pointers and references to arithmetic types are "
+ "not yet supported\n"));
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ if (elemType.IsArray())
+ {
+ LOG(("multidimensional arrays are not yet supported\n"));
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ return NS_OK;
+}
+
+static nsresult
+GetTypeSize(const nsXPTType &type, PRUint32 &size, PRBool &isSimple)
+{
+ // get the type size in bytes
+ size = 0;
+ isSimple = PR_TRUE;
+ switch (type.TagPart())
+ {
+ case nsXPTType::T_I8: size = sizeof(PRInt8); break;
+ case nsXPTType::T_I16: size = sizeof(PRInt16); break;
+ case nsXPTType::T_I32: size = sizeof(PRInt32); break;
+ case nsXPTType::T_I64: size = sizeof(PRInt64); break;
+ case nsXPTType::T_U8: size = sizeof(PRUint8); break;
+ case nsXPTType::T_U16: size = sizeof(PRUint16); break;
+ case nsXPTType::T_U32: size = sizeof(PRUint32); break;
+ case nsXPTType::T_U64: size = sizeof(PRUint64); break;
+ case nsXPTType::T_FLOAT: size = sizeof(float); break;
+ case nsXPTType::T_DOUBLE: size = sizeof(double); break;
+ case nsXPTType::T_BOOL: size = sizeof(PRBool); break;
+ case nsXPTType::T_CHAR: size = sizeof(char); break;
+ case nsXPTType::T_WCHAR: size = sizeof(PRUnichar); break;
+ case nsXPTType::T_IID: /* fall through */
+ case nsXPTType::T_CHAR_STR: /* fall through */
+ case nsXPTType::T_WCHAR_STR: /* fall through */
+ case nsXPTType::T_ASTRING: /* fall through */
+ case nsXPTType::T_DOMSTRING: /* fall through */
+ case nsXPTType::T_UTF8STRING: /* fall through */
+ case nsXPTType::T_CSTRING: /* fall through */
+ size = sizeof(void *);
+ isSimple = PR_FALSE;
+ break;
+ case nsXPTType::T_INTERFACE: /* fall through */
+ case nsXPTType::T_INTERFACE_IS: /* fall through */
+ size = sizeof(DConAddr);
+ isSimple = PR_FALSE;
+ break;
+ default:
+ LOG(("unexpected parameter type: %d\n", type.TagPart()));
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return NS_OK;
+}
+
+static nsresult
+SerializeArrayParam(ipcDConnectService *dConnect,
+ ipcMessageWriter &writer, PRUint32 peerID,
+ nsIInterfaceInfo *iinfo, uint16 methodIndex,
+ const nsXPTMethodInfo &methodInfo,
+ nsXPTCMiniVariant *params, PRBool isXPTCVariantArray,
+ const nsXPTParamInfo &paramInfo,
+ void *array, nsVoidArray &wrappers)
+{
+ if (!array)
+ {
+ // put 0 to indicate null array
+ writer.PutInt8(0);
+ return NS_OK;
+ }
+
+ // put 1 to indicate non-null array
+ writer.PutInt8(1);
+
+ PRUint32 size = 0;
+ PRUint32 length = 0;
+ nsXPTType elemType;
+
+ nsresult rv = GetArrayParamInfo(iinfo, methodIndex, methodInfo, params,
+ isXPTCVariantArray, paramInfo, PR_FALSE,
+ size, length, elemType);
+ if (NS_FAILED (rv))
+ return rv;
+
+ PRUint32 elemSize = 0;
+ PRBool isSimple = PR_TRUE;
+ rv = GetTypeSize(elemType, elemSize, isSimple);
+ if (NS_FAILED (rv))
+ return rv;
+
+ if (isSimple)
+ {
+ // this is a simple arithmetic type, write the whole array at once
+ writer.PutBytes(array, length * elemSize);
+ return NS_OK;
+ }
+
+ // iterate over valid (length_is) elements of the array
+ // and serialize each of them
+ nsXPTCMiniVariant v;
+ for (PRUint32 i = 0; i < length; ++i)
+ {
+ v.val.p = ((void **) array) [i];
+
+ if (elemType.IsInterfacePointer())
+ {
+ nsID iid;
+ rv = dConnect->GetIIDForMethodParam(iinfo, &methodInfo, paramInfo, elemType,
+ methodIndex, params, isXPTCVariantArray,
+ iid);
+ if (NS_SUCCEEDED(rv))
+ rv = dConnect->SerializeInterfaceParam(writer, peerID, iid,
+ (nsISupports *) v.val.p,
+ wrappers);
+ }
+ else
+ rv = SerializeParam(writer, elemType, v);
+
+ if (NS_FAILED(rv))
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+// isResult is PR_TRUE if the array param is out or retval
+static nsresult
+DeserializeArrayParam(ipcDConnectService *dConnect,
+ ipcMessageReader &reader, PRUint32 peerID,
+ nsIInterfaceInfo *iinfo, uint16 methodIndex,
+ const nsXPTMethodInfo &methodInfo,
+ nsXPTCMiniVariant *params, PRBool isXPTCVariantArray,
+ const nsXPTParamInfo &paramInfo,
+ PRBool isResult, void *&array)
+{
+ PRUint32 size = 0;
+ PRUint32 length = 0;
+ nsXPTType elemType;
+
+ nsresult rv = GetArrayParamInfo(iinfo, methodIndex, methodInfo, params,
+ isXPTCVariantArray, paramInfo, isResult,
+ size, length, elemType);
+ if (NS_FAILED(rv))
+ return rv;
+
+ PRUint8 prefix = reader.GetInt8();
+ if (prefix == 0)
+ {
+ // it's a null array
+ array = nsnull;
+ return NS_OK;
+ }
+ // sanity
+ if (prefix != 1)
+ {
+ LOG(("unexpected array prefix: %u\n", prefix));
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ PRUint32 elemSize = 0;
+ PRBool isSimple = PR_TRUE;
+ rv = GetTypeSize(elemType, elemSize, isSimple);
+ if (NS_FAILED (rv))
+ return rv;
+
+ // Note: for zero-sized arrays, we use the size of 1 because whether
+ // malloc(0) returns a null pointer or not (which is used in isNull())
+ // is implementation-dependent according to the C standard
+ void *arr = nsMemory::Alloc((size ? size : 1) * elemSize);
+ if (arr == nsnull)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // initialize the unused space of the array with zeroes
+ if (length < size)
+ memset(((PRUint8 *) arr) + length * elemSize, 0,
+ (size - length) * elemSize);
+
+ if (isSimple)
+ {
+ // this is a simple arithmetic type, read the whole array at once
+ reader.GetBytes(arr, length * elemSize);
+
+ array = arr;
+ return NS_OK;
+ }
+
+ // iterate over valid (length_is) elements of the array
+ // and deserialize each of them individually
+ nsXPTCVariant v;
+ for (PRUint32 i = 0; i < length; ++i)
+ {
+ rv = DeserializeParam(reader, elemType, v);
+
+ if (NS_SUCCEEDED(rv) && elemType.IsInterfacePointer())
+ {
+ // grab the DConAddr value temporarily stored in the param
+ PtrBits bits = v.val.u64;
+
+ // DeserializeInterfaceParamBits needs IID only if it's a remote object
+ nsID iid;
+ if (bits & PTRBITS_REMOTE_BIT)
+ rv = dConnect->GetIIDForMethodParam(iinfo, &methodInfo, paramInfo,
+ elemType, methodIndex,
+ params, isXPTCVariantArray, iid);
+ if (NS_SUCCEEDED(rv))
+ {
+ nsISupports *obj = nsnull;
+ rv = dConnect->DeserializeInterfaceParamBits(bits, peerID, iid, obj);
+ if (NS_SUCCEEDED(rv))
+ v.val.p = obj;
+ }
+ }
+
+ if (NS_FAILED(rv))
+ break;
+
+ // note that we discard extended param informaton provided by nsXPTCVariant
+ // and will have to "reconstruct" it from the type tag in FinishArrayParam()
+ ((void **) arr) [i] = v.val.p;
+ }
+
+ if (NS_FAILED(rv))
+ nsMemory::Free(arr);
+ else
+ array = arr;
+
+ return rv;
+}
+
+static void
+FinishArrayParam(nsIInterfaceInfo *iinfo, uint16 methodIndex,
+ const nsXPTMethodInfo &methodInfo, nsXPTCMiniVariant *params,
+ PRBool isXPTCVariantArray, const nsXPTParamInfo &paramInfo,
+ const nsXPTCMiniVariant &arrayVal)
+{
+ // nothing to do for a null array
+ void *arr = arrayVal.val.p;
+ if (!arr)
+ return;
+
+ PRUint32 size = 0;
+ PRUint32 length = 0;
+ nsXPTType elemType;
+
+ // note that FinishArrayParam is called only from OnInvoke to free memory
+ // after the call has been served. When OnInvoke sets up out and retval
+ // parameters for the real method, it passes pointers to the nsXPTCMiniVariant
+ // elements of the params array themselves so that they will eventually
+ // receive the returned values. For this reason, both in 'in' param and
+ // 'out/retaval' param cases, size_is and length_is may be read by
+ // GetArrayParamInfo() by value. Therefore, isResult is always PR_FALSE.
+ nsresult rv = GetArrayParamInfo(iinfo, methodIndex, methodInfo, params,
+ isXPTCVariantArray, paramInfo, PR_FALSE,
+ size, length, elemType);
+ if (NS_FAILED (rv))
+ return;
+
+ nsXPTCVariant v;
+ v.ptr = nsnull;
+ v.flags = 0;
+
+ // iterate over valid (length_is) elements of the array
+ // and free each of them
+ for (PRUint32 i = 0; i < length; ++i)
+ {
+ v.type = elemType.TagPart();
+
+ switch (elemType.TagPart())
+ {
+ case nsXPTType::T_I8: /* fall through */
+ case nsXPTType::T_I16: /* fall through */
+ case nsXPTType::T_I32: /* fall through */
+ case nsXPTType::T_I64: /* fall through */
+ case nsXPTType::T_U8: /* fall through */
+ case nsXPTType::T_U16: /* fall through */
+ case nsXPTType::T_U32: /* fall through */
+ case nsXPTType::T_U64: /* fall through */
+ case nsXPTType::T_FLOAT: /* fall through */
+ case nsXPTType::T_DOUBLE: /* fall through */
+ case nsXPTType::T_BOOL: /* fall through */
+ case nsXPTType::T_CHAR: /* fall through */
+ case nsXPTType::T_WCHAR: /* fall through */
+ // nothing to free for arithmetic types
+ continue;
+ case nsXPTType::T_IID: /* fall through */
+ case nsXPTType::T_CHAR_STR: /* fall through */
+ case nsXPTType::T_WCHAR_STR: /* fall through */
+ v.val.p = ((void **) arr) [i];
+ v.SetValIsAllocated();
+ break;
+ case nsXPTType::T_INTERFACE: /* fall through */
+ case nsXPTType::T_INTERFACE_IS: /* fall through */
+ v.val.p = ((void **) arr) [i];
+ v.SetValIsInterface();
+ break;
+ case nsXPTType::T_ASTRING: /* fall through */
+ case nsXPTType::T_DOMSTRING: /* fall through */
+ v.val.p = ((void **) arr) [i];
+ v.SetValIsDOMString();
+ break;
+ case nsXPTType::T_UTF8STRING: /* fall through */
+ v.val.p = ((void **) arr) [i];
+ v.SetValIsUTF8String();
+ break;
+ case nsXPTType::T_CSTRING: /* fall through */
+ v.val.p = ((void **) arr) [i];
+ v.SetValIsCString();
+ break;
+ default:
+ LOG(("unexpected parameter type: %d\n", elemType.TagPart()));
+ return;
+ }
+
+ FinishParam(v);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+static PRUint32
+NewRequestIndex()
+{
+ static PRInt32 sRequestIndex;
+ return (PRUint32) PR_AtomicIncrement(&sRequestIndex);
+}
+
+//-----------------------------------------------------------------------------
+
+#ifdef VBOX
+typedef struct ClientDownInfo
+{
+ ClientDownInfo(PRUint32 aClient)
+ {
+ uClient = aClient;
+ uTimestamp = PR_IntervalNow();
+ }
+
+ PRUint32 uClient;
+ PRIntervalTime uTimestamp;
+} ClientDownInfo;
+typedef std::map<PRUint32, ClientDownInfo *> ClientDownMap;
+typedef std::list<ClientDownInfo *> ClientDownList;
+
+#define MAX_CLIENT_DOWN_SIZE 10000
+
+/* Protected by the queue monitor. */
+static ClientDownMap g_ClientDownMap;
+static ClientDownList g_ClientDownList;
+
+#endif /* VBOX */
+
+class DConnectMsgSelector : public ipcIMessageObserver
+{
+public:
+ DConnectMsgSelector(PRUint32 peer, PRUint8 opCodeMajor, PRUint32 requestIndex)
+ : mPeer (peer)
+ , mOpCodeMajor(opCodeMajor)
+ , mRequestIndex(requestIndex)
+ {}
+
+ // stack based only
+ NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
+ NS_IMETHOD_(nsrefcnt) Release() { return 1; }
+
+ NS_IMETHOD QueryInterface(const nsIID &aIID, void **aInstancePtr);
+
+ NS_IMETHOD OnMessageAvailable(PRUint32 aSenderID, const nsID &aTarget,
+ const PRUint8 *aData, PRUint32 aDataLen)
+ {
+ // accept special "client dead" messages for a given peer
+ // (empty target id, zero data and data length)
+#ifndef VBOX
+ if (aSenderID == mPeer && aTarget.Equals(nsID()) && !aData && !aDataLen)
+ return NS_OK;
+#else /* VBOX */
+ if (aSenderID != IPC_SENDER_ANY && aTarget.Equals(nsID()) && !aData && !aDataLen)
+ {
+ // Insert new client down information. Start by expiring outdated
+ // entries and free one element if there's still no space (if needed).
+ PRIntervalTime now = PR_IntervalNow();
+ while (!g_ClientDownList.empty())
+ {
+ ClientDownInfo *cInfo = g_ClientDownList.back();
+ PRInt64 diff = (PRInt64)now - cInfo->uTimestamp;
+ if (diff < 0)
+ diff += (PRInt64)((PRIntervalTime)-1) + 1;
+ if (diff > PR_SecondsToInterval(15 * 60))
+ {
+ g_ClientDownMap.erase(cInfo->uClient);
+ g_ClientDownList.pop_back();
+ NS_ASSERTION(g_ClientDownMap.size() == g_ClientDownList.size(),
+ "client down info inconsistency during expiry");
+ delete cInfo;
+ }
+ else
+ break;
+ }
+
+ ClientDownMap::iterator it = g_ClientDownMap.find(aSenderID);
+ if (it == g_ClientDownMap.end())
+ {
+ /* Getting size of a map is O(1), size of a list can be O(n). */
+ while (g_ClientDownMap.size() >= MAX_CLIENT_DOWN_SIZE)
+ {
+ ClientDownInfo *cInfo = g_ClientDownList.back();
+ g_ClientDownMap.erase(cInfo->uClient);
+ g_ClientDownList.pop_back();
+ NS_ASSERTION(g_ClientDownMap.size() == g_ClientDownList.size(),
+ "client down info inconsistency during emergency evicting");
+ delete cInfo;
+ }
+
+ ClientDownInfo *cInfo = new ClientDownInfo(aSenderID);
+ RTMEM_MAY_LEAK(cInfo); /* tstVBoxAPIPerf leaks one allocated during ComPtr<IVirtualBoxClient>::createInprocObject(). */
+ g_ClientDownMap[aSenderID] = cInfo;
+ g_ClientDownList.push_front(cInfo);
+ NS_ASSERTION(g_ClientDownMap.size() == g_ClientDownList.size(),
+ "client down info inconsistency after adding entry");
+ }
+ return (aSenderID == mPeer) ? NS_OK : IPC_WAIT_NEXT_MESSAGE;
+ }
+ // accept special "client up" messages for a given peer
+ // (empty target id, zero data and data length=1)
+ if (aTarget.Equals(nsID()) && !aData && aDataLen == 1)
+ {
+ ClientDownMap::iterator it = g_ClientDownMap.find(aSenderID);
+ if (it != g_ClientDownMap.end())
+ {
+ ClientDownInfo *cInfo = it->second;
+ g_ClientDownMap.erase(it);
+ g_ClientDownList.remove(cInfo);
+ NS_ASSERTION(g_ClientDownMap.size() == g_ClientDownList.size(),
+ "client down info inconsistency in client up case");
+ delete cInfo;
+ }
+ return (aSenderID == mPeer) ? NS_OK : IPC_WAIT_NEXT_MESSAGE;
+ }
+ // accept special "client check" messages for an anonymous sender
+ // (invalid sender id, empty target id, zero data and data length
+ if (aSenderID == IPC_SENDER_ANY && aTarget.Equals(nsID()) && !aData && !aDataLen)
+ {
+ LOG(("DConnectMsgSelector::OnMessageAvailable: poll liveness for mPeer=%d\n",
+ mPeer));
+ ClientDownMap::iterator it = g_ClientDownMap.find(mPeer);
+ return (it == g_ClientDownMap.end()) ? IPC_WAIT_NEXT_MESSAGE : NS_OK;
+ }
+#endif /* VBOX */
+ const DConnectOp *op = (const DConnectOp *) aData;
+ // accept only reply messages with the given peer/opcode/index
+ // (to prevent eating replies the other thread might be waiting for)
+ // as well as any non-reply messages (to serve external requests that
+ // might arrive while we're waiting for the given reply).
+ if (aDataLen >= sizeof(DConnectOp) &&
+ ((op->opcode_major != DCON_OP_SETUP_REPLY &&
+ op->opcode_major != DCON_OP_INVOKE_REPLY) ||
+ (aSenderID == mPeer &&
+ op->opcode_major == mOpCodeMajor &&
+ op->request_index == mRequestIndex)))
+ return NS_OK;
+ else
+ return IPC_WAIT_NEXT_MESSAGE;
+ }
+
+ const PRUint32 mPeer;
+ const PRUint8 mOpCodeMajor;
+ const PRUint32 mRequestIndex;
+};
+NS_IMPL_QUERY_INTERFACE1(DConnectMsgSelector, ipcIMessageObserver)
+
+class DConnectCompletion : public ipcIMessageObserver
+{
+public:
+ DConnectCompletion(PRUint32 peer, PRUint8 opCodeMajor, PRUint32 requestIndex)
+ : mSelector(peer, opCodeMajor, requestIndex)
+ {}
+
+ // stack based only
+ NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
+ NS_IMETHOD_(nsrefcnt) Release() { return 1; }
+
+ NS_IMETHOD QueryInterface(const nsIID &aIID, void **aInstancePtr);
+
+ NS_IMETHOD OnMessageAvailable(PRUint32 aSenderID, const nsID &aTarget,
+ const PRUint8 *aData, PRUint32 aDataLen)
+ {
+ const DConnectOp *op = (const DConnectOp *) aData;
+ LOG((
+ "DConnectCompletion::OnMessageAvailable: "
+ "senderID=%d, opcode_major=%d, index=%d (waiting for %d)\n",
+ aSenderID, op->opcode_major, op->request_index, mSelector.mRequestIndex
+ ));
+ if (aSenderID == mSelector.mPeer &&
+ op->opcode_major == mSelector.mOpCodeMajor &&
+ op->request_index == mSelector.mRequestIndex)
+ {
+ OnResponseAvailable(aSenderID, op, aDataLen);
+ }
+ else
+ {
+ // ensure ipcDConnectService is not deleted before we finish
+ nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+ if (dConnect)
+ dConnect->OnMessageAvailable(aSenderID, aTarget, aData, aDataLen);
+ }
+ return NS_OK;
+ }
+
+ virtual void OnResponseAvailable(PRUint32 sender, const DConnectOp *op, PRUint32 opLen) = 0;
+
+ DConnectMsgSelector &GetSelector()
+ {
+ return mSelector;
+ }
+
+protected:
+ DConnectMsgSelector mSelector;
+};
+NS_IMPL_QUERY_INTERFACE1(DConnectCompletion, ipcIMessageObserver)
+
+//-----------------------------------------------------------------------------
+
+class DConnectInvokeCompletion : public DConnectCompletion
+{
+public:
+ DConnectInvokeCompletion(PRUint32 peer, const DConnectInvoke *invoke)
+ : DConnectCompletion(peer, DCON_OP_INVOKE_REPLY, invoke->request_index)
+ , mReply(nsnull)
+ , mParamsLen(0)
+ {}
+
+ ~DConnectInvokeCompletion() { if (mReply) free(mReply); }
+
+ void OnResponseAvailable(PRUint32 sender, const DConnectOp *op, PRUint32 opLen)
+ {
+ mReply = (DConnectInvokeReply *) malloc(opLen);
+ memcpy(mReply, op, opLen);
+
+ // the length in bytes of the parameter blob
+ mParamsLen = opLen - sizeof(*mReply);
+ }
+
+ PRBool IsPending() const { return mReply == nsnull; }
+ nsresult GetResult() const { return mReply->result; }
+
+ const PRUint8 *Params() const { return (const PRUint8 *) (mReply + 1); }
+ PRUint32 ParamsLen() const { return mParamsLen; }
+
+ const DConnectInvokeReply *Reply() const { return mReply; }
+
+private:
+ DConnectInvokeReply *mReply;
+ PRUint32 mParamsLen;
+};
+
+//-----------------------------------------------------------------------------
+
+#define DCONNECT_STUB_ID \
+{ /* 132c1f14-5442-49cb-8fe6-e60214bbf1db */ \
+ 0x132c1f14, \
+ 0x5442, \
+ 0x49cb, \
+ {0x8f, 0xe6, 0xe6, 0x02, 0x14, 0xbb, 0xf1, 0xdb} \
+}
+static NS_DEFINE_IID(kDConnectStubID, DCONNECT_STUB_ID);
+
+// this class represents the non-local object instance.
+
+class DConnectStub : public nsXPTCStubBase
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ DConnectStub(nsIInterfaceInfo *aIInfo,
+ DConAddr aInstance,
+ PRUint32 aPeerID)
+ : mIInfo(aIInfo)
+ , mInstance(aInstance)
+ , mPeerID(aPeerID)
+ , mCachedISupports(0)
+ , mRefCntLevels(0)
+ {}
+
+ NS_HIDDEN ~DConnectStub();
+
+ // return a refcounted pointer to the InterfaceInfo for this object
+ // NOTE: on some platforms this MUST not fail or we crash!
+ NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo **aInfo);
+
+ // call this method and return result
+ NS_IMETHOD CallMethod(PRUint16 aMethodIndex,
+ const nsXPTMethodInfo *aInfo,
+ nsXPTCMiniVariant *aParams);
+
+ DConAddr Instance() { return mInstance; }
+ PRUint32 PeerID() { return mPeerID; }
+
+ DConnectStubKey::Key GetKey() {
+ return DConnectStubKey::Key(mPeerID, mInstance);
+ }
+
+ NS_IMETHOD_(nsrefcnt) AddRefIPC();
+
+private:
+ nsCOMPtr<nsIInterfaceInfo> mIInfo;
+
+ // uniquely identifies this object instance between peers.
+ DConAddr mInstance;
+
+ // the "client id" of our IPC peer. this guy owns the real object.
+ PRUint32 mPeerID;
+
+ // cached nsISupports stub for this object
+ DConnectStub *mCachedISupports;
+
+ // stack of reference counter values (protected by
+ // ipcDConnectService::StubLock())
+ nsDeque mRefCntLevels;
+};
+
+NS_IMETHODIMP_(nsrefcnt)
+DConnectStub::AddRefIPC()
+{
+ // in this special version, we memorize the resulting reference count in the
+ // associated stack array. This stack is then used by Release() to determine
+ // when it is necessary to send a RELEASE request to the peer owning the
+ // object in order to balance AddRef() the peer does on DConnectInstance every
+ // time it passes an object over IPC.
+
+ // NOTE: this function is to be called from DConnectInstance::CreateStub only!
+
+ nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+ NS_ASSERTION(dConnect, "no ipcDConnectService (uninitialized?)");
+ if (!dConnect)
+ return 0;
+
+ // dConnect->StubLock() must be already locked here by
+ // DConnectInstance::CreateStub
+
+ nsrefcnt count = AddRef();
+ mRefCntLevels.Push((void *)(uintptr_t) count);
+ return count;
+}
+
+nsresult
+ipcDConnectService::CreateStub(const nsID &iid, PRUint32 peer, DConAddr instance,
+ DConnectStub **result)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIInterfaceInfo> iinfo;
+ rv = GetInterfaceInfo(iid, getter_AddRefs(iinfo));
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsAutoLock lock (mLock);
+
+ if (mDisconnected)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ // we also need the stub lock which protects DConnectStub::mRefCntLevels and
+ // ipcDConnectService::mStubs
+ nsAutoLock stubLock (mStubLock);
+
+ DConnectStub *stub = nsnull;
+
+ // first try to find an existing stub for a given peer and instance
+ // (we do not care about IID because every DConAddr instance represents
+ // exactly one interface of the real object on the peer's side)
+ if (!mStubs.Get(DConnectStubKey::Key(peer, instance), &stub))
+ {
+ stub = new DConnectStub(iinfo, instance, peer);
+
+ if (NS_UNLIKELY(!stub))
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ else
+ {
+ rv = StoreStub(stub);
+ if (NS_FAILED(rv))
+ delete stub;
+ }
+ }
+
+ if (NS_SUCCEEDED(rv))
+ {
+ stub->AddRefIPC();
+ *result = stub;
+ }
+
+ return rv;
+}
+
+nsresult
+ipcDConnectService::SerializeInterfaceParam(ipcMessageWriter &writer,
+ PRUint32 peer, const nsID &iid,
+ nsISupports *obj,
+ nsVoidArray &wrappers)
+{
+ nsAutoLock lock (mLock);
+
+ if (mDisconnected)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ // we create an instance wrapper, and assume that the other side will send a
+ // RELEASE message when it no longer needs the instance wrapper. that will
+ // usually happen after the call returns.
+ //
+ // XXX a lazy scheme might be better, but for now simplicity wins.
+
+ // if the interface pointer references a DConnectStub corresponding
+ // to an object in the address space of the peer, then no need to
+ // create a new wrapper.
+
+ // if the interface pointer references an object for which we already have
+ // an existing wrapper, then we use it instead of creating a new one. this
+ // is based on the assumption that a valid COM object always returns exactly
+ // the same pointer value in response to every
+ // QueryInterface(NS_GET_IID(nsISupports), ...).
+
+ if (!obj)
+ {
+ // write null address
+ DConAddr nullobj = 0;
+ writer.PutBytes(&nullobj, sizeof(nullobj));
+ }
+ else
+ {
+ DConnectStub *stub = nsnull;
+ nsresult rv = obj->QueryInterface(kDConnectStubID, (void **) &stub);
+ if (NS_SUCCEEDED(rv) && (stub->PeerID() == peer))
+ {
+ DConAddr p = stub->Instance();
+ writer.PutBytes(&p, sizeof(p));
+ }
+ else
+ {
+ // create instance wrapper
+
+ nsCOMPtr<nsIInterfaceInfo> iinfo;
+ rv = GetInterfaceInfo(iid, getter_AddRefs(iinfo));
+ if (NS_FAILED(rv))
+ return rv;
+
+ DConnectInstance *wrapper = nsnull;
+
+ // first try to find an existing wrapper for the given object
+ if (!FindInstanceAndAddRef(peer, obj, &iid, &wrapper))
+ {
+ wrapper = new DConnectInstance(peer, iinfo, obj);
+ if (!wrapper)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ rv = StoreInstance(wrapper);
+ if (NS_FAILED(rv))
+ {
+ delete wrapper;
+ return rv;
+ }
+
+ // reference the newly created wrapper
+ wrapper->AddRef();
+ }
+
+ // increase the second, IPC-only, reference counter (mandatory before
+ // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove
+ // the wrapper from the instance map on failure)
+ wrapper->AddRefIPC();
+
+ if (!wrappers.AppendElement(wrapper))
+ {
+ wrapper->ReleaseIPC();
+ wrapper->Release();
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ // wrapper remains referenced when passing it to the client
+ // (will be released upon DCON_OP_RELEASE)
+
+ // send address of the instance wrapper, and set the low bit to indicate
+ // to the remote party that this is a remote instance wrapper.
+ PtrBits bits = ((PtrBits)(uintptr_t) wrapper);
+ NS_ASSERTION((bits & PTRBITS_REMOTE_BIT) == 0, "remote bit wrong)");
+ bits |= PTRBITS_REMOTE_BIT;
+ writer.PutBytes(&bits, sizeof(bits));
+ }
+ NS_IF_RELEASE(stub);
+ }
+ return NS_OK;
+}
+
+// NOTE: peer and iid are ignored if bits doesn't contain PTRBITS_REMOTE_BIT
+nsresult
+ipcDConnectService::DeserializeInterfaceParamBits(PtrBits bits, PRUint32 peer,
+ const nsID &iid,
+ nsISupports *&obj)
+{
+ nsresult rv;
+
+ obj = nsnull;
+
+ if (bits & PTRBITS_REMOTE_BIT)
+ {
+ // pointer is to a remote object. we need to build a stub.
+
+ bits &= ~PTRBITS_REMOTE_BIT;
+
+ DConnectStub *stub;
+ rv = CreateStub(iid, peer, (DConAddr) bits, &stub);
+ if (NS_SUCCEEDED(rv))
+ obj = stub;
+ }
+ else if (bits)
+ {
+ // pointer is to one of our instance wrappers. Replace it with the
+ // real instance.
+
+ DConnectInstance *wrapper = (DConnectInstance *) bits;
+ // make sure we've been sent a valid wrapper
+ if (!CheckInstanceAndAddRef(wrapper, peer))
+ {
+ NS_NOTREACHED("instance wrapper not found");
+ return NS_ERROR_INVALID_ARG;
+ }
+ obj = wrapper->RealInstance();
+ NS_ADDREF(obj);
+ NS_RELEASE(wrapper);
+ }
+ else
+ {
+ // obj is alredy nsnull
+ }
+
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+
+#define EXCEPTION_STUB_ID \
+{ /* 70578d68-b25e-4370-a70c-89bbe56e6699 */ \
+ 0x70578d68, \
+ 0xb25e, \
+ 0x4370, \
+ {0xa7, 0x0c, 0x89, 0xbb, 0xe5, 0x6e, 0x66, 0x99} \
+}
+static NS_DEFINE_IID(kExceptionStubID, EXCEPTION_STUB_ID);
+
+// ExceptionStub is used to cache all primitive-typed bits of a remote nsIException
+// instance (such as the error message or line number) to:
+//
+// a) reduce the number of IPC calls;
+// b) make sure exception information is available to the calling party even if
+// the called party terminates immediately after returning an exception.
+// To achieve this, all cacheable information is serialized together with
+// the instance wrapper itself.
+
+class ExceptionStub : public nsIException
+{
+public:
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIEXCEPTION
+
+ ExceptionStub(const nsACString &aMessage, nsresult aResult,
+ const nsACString &aName, const nsACString &aFilename,
+ PRUint32 aLineNumber, PRUint32 aColumnNumber,
+ DConnectStub *aXcptStub)
+ : mMessage(aMessage), mResult(aResult)
+ , mName(aName), mFilename(aFilename)
+ , mLineNumber (aLineNumber), mColumnNumber (aColumnNumber)
+ , mXcptStub (aXcptStub) { NS_ASSERTION(aXcptStub, "NULL"); }
+
+ ~ExceptionStub() {}
+
+ nsIException *Exception() { return (nsIException *)(nsISupports *) mXcptStub; }
+ DConnectStub *Stub() { return mXcptStub; }
+
+private:
+
+ nsCString mMessage;
+ nsresult mResult;
+ nsCString mName;
+ nsCString mFilename;
+ PRUint32 mLineNumber;
+ PRUint32 mColumnNumber;
+ nsRefPtr<DConnectStub> mXcptStub;
+};
+
+NS_IMPL_THREADSAFE_ADDREF(ExceptionStub)
+NS_IMPL_THREADSAFE_RELEASE(ExceptionStub)
+
+NS_IMETHODIMP
+ExceptionStub::QueryInterface(const nsID &aIID, void **aInstancePtr)
+{
+ NS_ASSERTION(aInstancePtr,
+ "QueryInterface requires a non-NULL destination!");
+
+ // used to discover if this is an ExceptionStub instance.
+ if (aIID.Equals(kExceptionStubID))
+ {
+ *aInstancePtr = this;
+ NS_ADDREF_THIS();
+ return NS_OK;
+ }
+
+ // regular NS_IMPL_QUERY_INTERFACE1 sequence
+
+ nsISupports* foundInterface = 0;
+
+ if (aIID.Equals(NS_GET_IID(nsIException)))
+ foundInterface = NS_STATIC_CAST(nsIException*, this);
+ else
+ if (aIID.Equals(NS_GET_IID(nsISupports)))
+ foundInterface = NS_STATIC_CAST(nsISupports*,
+ NS_STATIC_CAST(nsIException *, this));
+ else
+ if (mXcptStub)
+ {
+ // ask the real nsIException object
+ return mXcptStub->QueryInterface(aIID, aInstancePtr);
+ }
+
+ nsresult status;
+ if (!foundInterface)
+ status = NS_NOINTERFACE;
+ else
+ {
+ NS_ADDREF(foundInterface);
+ status = NS_OK;
+ }
+ *aInstancePtr = foundInterface;
+ return status;
+}
+
+/* readonly attribute string message; */
+NS_IMETHODIMP ExceptionStub::GetMessage(char **aMessage)
+{
+ AssertReturn(aMessage, NS_ERROR_INVALID_POINTER);
+ *aMessage = ToNewCString(mMessage);
+ return NS_OK;
+}
+
+/* readonly attribute nsresult result; */
+NS_IMETHODIMP ExceptionStub::GetResult(nsresult *aResult)
+{
+ AssertReturn(aResult, NS_ERROR_INVALID_POINTER);
+ *aResult = mResult;
+ return NS_OK;
+}
+
+/* readonly attribute string name; */
+NS_IMETHODIMP ExceptionStub::GetName(char **aName)
+{
+ AssertReturn(aName, NS_ERROR_INVALID_POINTER);
+ *aName = ToNewCString(mName);
+ return NS_OK;
+}
+
+/* readonly attribute string filename; */
+NS_IMETHODIMP ExceptionStub::GetFilename(char **aFilename)
+{
+ AssertReturn(aFilename, NS_ERROR_INVALID_POINTER);
+ *aFilename = ToNewCString(mFilename);
+ return NS_OK;
+}
+
+/* readonly attribute PRUint32 lineNumber; */
+NS_IMETHODIMP ExceptionStub::GetLineNumber(PRUint32 *aLineNumber)
+{
+ AssertReturn(aLineNumber, NS_ERROR_INVALID_POINTER);
+ *aLineNumber = mLineNumber;
+ return NS_OK;
+}
+
+/* readonly attribute PRUint32 columnNumber; */
+NS_IMETHODIMP ExceptionStub::GetColumnNumber(PRUint32 *aColumnNumber)
+{
+ AssertReturn(aColumnNumber, NS_ERROR_INVALID_POINTER);
+ *aColumnNumber = mColumnNumber;
+ return NS_OK;
+}
+
+/* readonly attribute nsIStackFrame location; */
+NS_IMETHODIMP ExceptionStub::GetLocation(nsIStackFrame **aLocation)
+{
+ if (Exception())
+ return Exception()->GetLocation (aLocation);
+ return NS_ERROR_UNEXPECTED;
+}
+
+/* readonly attribute nsIException inner; */
+NS_IMETHODIMP ExceptionStub::GetInner(nsIException **aInner)
+{
+ if (Exception())
+ return Exception()->GetInner (aInner);
+ return NS_ERROR_UNEXPECTED;
+}
+
+/* readonly attribute nsISupports data; */
+NS_IMETHODIMP ExceptionStub::GetData(nsISupports * *aData)
+{
+ if (Exception())
+ return Exception()->GetData (aData);
+ return NS_ERROR_UNEXPECTED;
+}
+
+/* string toString (); */
+NS_IMETHODIMP ExceptionStub::ToString(char **_retval)
+{
+ if (Exception())
+ return Exception()->ToString (_retval);
+ return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
+ipcDConnectService::SerializeException(ipcMessageWriter &writer,
+ PRUint32 peer, nsIException *xcpt,
+ nsVoidArray &wrappers)
+{
+ PRBool cache_fields = PR_FALSE;
+
+ // first, seralize the nsIException pointer. The code is merely the same as
+ // in SerializeInterfaceParam() except that when the exception to serialize
+ // is an ExceptionStub instance and the real instance it stores as mXcpt
+ // is a DConnectStub corresponding to an object in the address space of the
+ // peer, we simply pass that object back instead of creating a new wrapper.
+
+ {
+ nsAutoLock lock (mLock);
+
+ if (mDisconnected)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ if (!xcpt)
+ {
+ // write null address
+#ifdef VBOX
+ // see ipcDConnectService::DeserializeException()!
+ PtrBits bits = 0;
+ writer.PutBytes(&bits, sizeof(bits));
+#else
+ writer.PutBytes(&xcpt, sizeof(xcpt));
+#endif
+ }
+ else
+ {
+ ExceptionStub *stub = nsnull;
+ nsresult rv = xcpt->QueryInterface(kExceptionStubID, (void **) &stub);
+ if (NS_SUCCEEDED(rv) && (stub->Stub()->PeerID() == peer))
+ {
+ // send the wrapper instance back to the peer
+ DConAddr p = stub->Stub()->Instance();
+ writer.PutBytes(&p, sizeof(p));
+ }
+ else
+ {
+ // create instance wrapper
+
+ const nsID &iid = nsIException::GetIID();
+ nsCOMPtr<nsIInterfaceInfo> iinfo;
+ rv = GetInterfaceInfo(iid, getter_AddRefs(iinfo));
+ if (NS_FAILED(rv))
+ return rv;
+
+ DConnectInstance *wrapper = nsnull;
+
+ // first try to find an existing wrapper for the given object
+ if (!FindInstanceAndAddRef(peer, xcpt, &iid, &wrapper))
+ {
+ wrapper = new DConnectInstance(peer, iinfo, xcpt);
+ if (!wrapper)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ rv = StoreInstance(wrapper);
+ if (NS_FAILED(rv))
+ {
+ delete wrapper;
+ return rv;
+ }
+
+ // reference the newly created wrapper
+ wrapper->AddRef();
+ }
+
+ // increase the second, IPC-only, reference counter (mandatory before
+ // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove
+ // the wrapper from the instance map on failure)
+ wrapper->AddRefIPC();
+
+ if (!wrappers.AppendElement(wrapper))
+ {
+ wrapper->ReleaseIPC();
+ wrapper->Release();
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ // wrapper remains referenced when passing it to the client
+ // (will be released upon DCON_OP_RELEASE)
+
+ // send address of the instance wrapper, and set the low bit to indicate
+ // to the remote party that this is a remote instance wrapper.
+ PtrBits bits = ((PtrBits)(uintptr_t) wrapper) | PTRBITS_REMOTE_BIT;
+ writer.PutBytes(&bits, sizeof(bits));
+
+ // we want to cache fields to minimize the number of IPC calls when
+ // accessing exception data on the peer side
+ cache_fields = PR_TRUE;
+ }
+ NS_IF_RELEASE(stub);
+ }
+ }
+
+ if (!cache_fields)
+ return NS_OK;
+
+ nsresult rv;
+ nsXPIDLCString str;
+ PRUint32 num;
+
+ // message
+ rv = xcpt->GetMessage(getter_Copies(str));
+ if (NS_SUCCEEDED (rv))
+ {
+ PRUint32 len = str.Length();
+ nsACString::const_iterator begin;
+ const char *data = str.BeginReading(begin).get();
+ writer.PutInt32(len);
+ writer.PutBytes(data, len);
+ }
+ else
+ writer.PutInt32(0);
+
+ // result
+ nsresult res = 0;
+ xcpt->GetResult(&res);
+ writer.PutInt32(res);
+
+ // name
+ rv = xcpt->GetName(getter_Copies(str));
+ if (NS_SUCCEEDED (rv))
+ {
+ PRUint32 len = str.Length();
+ nsACString::const_iterator begin;
+ const char *data = str.BeginReading(begin).get();
+ writer.PutInt32(len);
+ writer.PutBytes(data, len);
+ }
+ else
+ writer.PutInt32(0);
+
+ // filename
+ rv = xcpt->GetFilename(getter_Copies(str));
+ if (NS_SUCCEEDED (rv))
+ {
+ PRUint32 len = str.Length();
+ nsACString::const_iterator begin;
+ const char *data = str.BeginReading(begin).get();
+ writer.PutInt32(len);
+ writer.PutBytes(data, len);
+ }
+ else
+ writer.PutInt32(0);
+
+ // lineNumber
+ num = 0;
+ xcpt->GetLineNumber(&num);
+ writer.PutInt32(num);
+
+ // columnNumber
+ num = 0;
+ xcpt->GetColumnNumber(&num);
+ writer.PutInt32(num);
+
+ return writer.HasError() ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
+}
+
+nsresult
+ipcDConnectService::DeserializeException(ipcMessageReader &reader,
+ PRUint32 peer,
+ nsIException **xcpt)
+{
+ NS_ASSERTION (xcpt, "NULL");
+ if (!xcpt)
+ return NS_ERROR_INVALID_POINTER;
+
+ nsresult rv;
+ PRUint32 len;
+
+ PtrBits bits = 0;
+ reader.GetBytes(&bits, sizeof(DConAddr));
+ if (reader.HasError())
+ return NS_ERROR_INVALID_ARG;
+
+ if (bits & PTRBITS_REMOTE_BIT)
+ {
+ // pointer is a peer-side exception instance wrapper,
+ // read cahced exception data and create a stub for it.
+
+ nsCAutoString message;
+ len = reader.GetInt32();
+ if (len)
+ {
+ message.SetLength(len);
+ char *buf = message.BeginWriting();
+ reader.GetBytes(buf, len);
+ }
+
+ nsresult result = reader.GetInt32();
+
+ nsCAutoString name;
+ len = reader.GetInt32();
+ if (len)
+ {
+ name.SetLength(len);
+ char *buf = name.BeginWriting();
+ reader.GetBytes(buf, len);
+ }
+
+ nsCAutoString filename;
+ len = reader.GetInt32();
+ if (len)
+ {
+ filename.SetLength(len);
+ char *buf = filename.BeginWriting();
+ reader.GetBytes(buf, len);
+ }
+
+ PRUint32 lineNumber = reader.GetInt32();
+ PRUint32 columnNumber = reader.GetInt32();
+
+ if (reader.HasError())
+ rv = NS_ERROR_INVALID_ARG;
+ else
+ {
+ DConAddr addr = (DConAddr) (bits & ~PTRBITS_REMOTE_BIT);
+ nsRefPtr<DConnectStub> stub;
+ rv = CreateStub(nsIException::GetIID(), peer, addr,
+ getter_AddRefs(stub));
+ if (NS_SUCCEEDED(rv))
+ {
+ // create a special exception "stub" with cached error info
+ ExceptionStub *xcptStub =
+ new ExceptionStub (message, result,
+ name, filename,
+ lineNumber, columnNumber,
+ stub);
+ if (xcptStub)
+ {
+ *xcpt = xcptStub;
+ NS_ADDREF(xcptStub);
+ }
+ else
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ }
+ else if (bits)
+ {
+ // pointer is to our instance wrapper for nsIException we've sent before
+ // (the remote method we've called had called us back and got an exception
+ // from us that it decided to return as its own result). Replace it with
+ // the real instance.
+ DConnectInstance *wrapper = (DConnectInstance *) bits;
+ if (CheckInstanceAndAddRef(wrapper, peer))
+ {
+ *xcpt = (nsIException *) wrapper->RealInstance();
+ NS_ADDREF(wrapper->RealInstance());
+ wrapper->Release();
+ rv = NS_OK;
+ }
+ else
+ {
+ NS_NOTREACHED("instance wrapper not found");
+ rv = NS_ERROR_INVALID_ARG;
+ }
+ }
+ else
+ {
+ // the peer explicitly passed us a NULL exception to indicate that the
+ // exception on the current thread should be reset
+ *xcpt = NULL;
+ return NS_OK;
+ }
+
+
+ return rv;
+}
+
+//-----------------------------------------------------------------------------
+
+DConnectStub::~DConnectStub()
+{
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name = NULL;
+ mIInfo->GetNameShared(&name);
+ LOG(("{%p} DConnectStub::<dtor>(): peer=%d instance=0x%Lx {%s}\n",
+ this, mPeerID, mInstance, name));
+ }
+#endif
+
+ // release the cached nsISupports instance if it's not the same object
+ if (mCachedISupports != 0 && mCachedISupports != this)
+ NS_RELEASE(mCachedISupports);
+}
+
+NS_IMETHODIMP_(nsrefcnt)
+DConnectStub::AddRef()
+{
+ nsrefcnt count;
+ count = PR_AtomicIncrement((PRInt32*)&mRefCnt);
+ NS_LOG_ADDREF(this, count, "DConnectStub", sizeof(*this));
+ return count;
+}
+
+NS_IMETHODIMP_(nsrefcnt)
+DConnectStub::Release()
+{
+ nsrefcnt count;
+
+ nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+ if (dConnect)
+ {
+ // lock the stub lock on every release to make sure that once the counter
+ // drops to zero, we delete the stub from the set of stubs before a new
+ // request to create a stub on other thread tries to find the existing
+ // stub in the set (wchich could otherwise AddRef the object after it had
+ // Released to zero and pass it to the client right before its
+ // destruction).
+ nsAutoLock stubLock (dConnect->StubLock());
+
+ count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
+ NS_LOG_RELEASE(this, count, "DConnectStub");
+
+
+ #ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name;
+ mIInfo->GetNameShared(&name);
+ LOG(("{%p} DConnectStub::Release(): peer=%d instance=0x%Lx {%s}, new count=%d\n",
+ this, mPeerID, mInstance, name, count));
+ }
+ #endif
+
+ // mRefCntLevels may already be empty here (due to the "stabilize" trick below)
+ if (mRefCntLevels.GetSize() > 0)
+ {
+ nsrefcnt top = (nsrefcnt) (long) mRefCntLevels.Peek();
+ NS_ASSERTION(top <= count + 1, "refcount is beyond the top level");
+
+ if (top == count + 1)
+ {
+ // refcount dropped to a value stored in ipcDConnectService::CreateStub.
+ // Send a RELEASE request to the peer (see also AddRefIPC).
+
+ // remove the top refcount value
+ mRefCntLevels.Pop();
+
+ if (0 == count)
+ {
+ // this is the last reference, remove from the set before we leave
+ // the lock, to provide atomicity of these two operations
+ dConnect->DeleteStub (this);
+
+ NS_ASSERTION(mRefCntLevels.GetSize() == 0, "refcnt levels are still left");
+ }
+
+ // leave the lock before sending a message
+ stubLock.unlock();
+
+ nsresult rv;
+
+ DConnectRelease msg;
+ msg.opcode_major = DCON_OP_RELEASE;
+ msg.opcode_minor = 0;
+ msg.flags = 0;
+ msg.request_index = 0; // not used, set to some unused value
+ msg.instance = mInstance;
+
+ // fire off asynchronously... we don't expect any response to this message.
+ rv = IPC_SendMessage(mPeerID, kDConnectTargetID,
+ (const PRUint8 *) &msg, sizeof(msg));
+ if (NS_FAILED(rv))
+ NS_WARNING("failed to send RELEASE event");
+ }
+ }
+ }
+ else
+ {
+ count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
+ NS_LOG_RELEASE(this, count, "DConnectStub");
+ }
+
+ if (0 == count)
+ {
+ mRefCnt = 1; /* stabilize */
+ delete this;
+ return 0;
+ }
+
+ return count;
+}
+
+NS_IMETHODIMP
+DConnectStub::QueryInterface(const nsID &aIID, void **aInstancePtr)
+{
+ // used to discover if this is a DConnectStub instance.
+ if (aIID.Equals(kDConnectStubID))
+ {
+ *aInstancePtr = this;
+ NS_ADDREF_THIS();
+ return NS_OK;
+ }
+
+ // In order to truely support the COM Identity Rule across processes,
+ // we need to make the following code work:
+ //
+ // IFoo *foo = ...
+ // nsISupports unk;
+ // foo->QueryInterface(NS_GET_IID(nsISupports), (void **) &unk);
+ // unk->Release();
+ // nsISupports unk2;
+ // foo->QueryInterface(NS_GET_IID(nsISupports), (void **) &unk2);
+ // Assert (unk == unk2);
+ //
+ // I.e. querying nsISupports on the same object must always return the same
+ // pointer, even if the nsISupports object returned for the first time is
+ // released before it is requested for the second time, as long as the
+ // original object is kept alive (referenced by the client) between these
+ // two queries.
+ //
+ // This is done by remembering the nsISupports stub returned by the peer
+ // when nsISupports is queried for the first time. The remembered stub, when
+ // it is not the same as this object, is strongly referenced in order to
+ // keep it alive (and therefore have the same pointer value) as long as this
+ // object is alive.
+ //
+ // Besides supporting the Identity Rule, this also reduces the number of IPC
+ // calls, since an IPC call requesting nsISupports will be done only once
+ // per every stub object.
+
+ nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+ NS_ASSERTION(dConnect, "no ipcDConnectService (uninitialized?)");
+ if (!dConnect)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ nsresult rv;
+ PRBool needISupports = aIID.Equals(NS_GET_IID(nsISupports));
+
+ if (needISupports)
+ {
+ // XXX it would be sufficient to use cmpxchg here to protect access to
+ // mCachedISupports, but NSPR doesn't provide cross-platform cmpxchg
+ // functionality, so we have to use a shared lock instead...
+ PR_Lock(dConnect->StubQILock());
+
+ // check if we have already got a nsISupports stub for this object
+ if (mCachedISupports != 0)
+ {
+ *aInstancePtr = mCachedISupports;
+ NS_ADDREF(mCachedISupports);
+
+ PR_Unlock(dConnect->StubQILock());
+ return NS_OK;
+ }
+
+ // check if this object is nsISupports itself
+ {
+ nsIID *iid = 0;
+ rv = mIInfo->GetInterfaceIID(&iid);
+ NS_ASSERTION(NS_SUCCEEDED(rv) && iid,
+ "nsIInterfaceInfo::GetInterfaceIID failed");
+ if (NS_SUCCEEDED(rv) && iid &&
+ iid->Equals(NS_GET_IID(nsISupports)))
+ {
+ nsMemory::Free((void*)iid);
+
+ // nsISupports is queried on nsISupports, return ourselves
+ *aInstancePtr = this;
+ NS_ADDREF_THIS();
+ // cache ourselves weakly
+ mCachedISupports = this;
+
+ PR_Unlock(dConnect->StubQILock());
+ return NS_OK;
+ }
+ if (iid)
+ nsMemory::Free((void*)iid);
+ }
+
+ // stub lock remains held until we've queried the peer
+ }
+
+ // else, we need to query the peer object by making an IPC call
+
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name;
+ mIInfo->GetNameShared(&name);
+ const char *nameQ;
+ nsCOMPtr <nsIInterfaceInfo> iinfoQ;
+ dConnect->GetInterfaceInfo(aIID, getter_AddRefs(iinfoQ));
+ if (iinfoQ) {
+ iinfoQ->GetNameShared(&nameQ);
+ LOG(("calling QueryInterface {%s} on peer object "
+ "(stub=%p, instance=0x%Lx {%s})\n",
+ nameQ, this, mInstance, name));
+ }
+ }
+#endif
+
+ DConnectSetupQueryInterface msg;
+ msg.opcode_minor = DCON_OP_SETUP_QUERY_INTERFACE;
+ msg.iid = aIID;
+ msg.instance = mInstance;
+
+ rv = SetupPeerInstance(mPeerID, &msg, sizeof(msg), aInstancePtr);
+
+ if (needISupports)
+ {
+ if (NS_SUCCEEDED(rv))
+ {
+ // cache the nsISupports object (SetupPeerInstance returns DConnectStub)
+ mCachedISupports = (DConnectStub *) *aInstancePtr;
+ // use a weak reference if nsISupports is the same object as us
+ if (this != mCachedISupports)
+ NS_ADDREF(mCachedISupports);
+ }
+
+ PR_Unlock(dConnect->StubQILock());
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+DConnectStub::GetInterfaceInfo(nsIInterfaceInfo **aInfo)
+{
+ NS_ADDREF(*aInfo = mIInfo);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+DConnectStub::CallMethod(PRUint16 aMethodIndex,
+ const nsXPTMethodInfo *aInfo,
+ nsXPTCMiniVariant *aParams)
+{
+ LOG(("DConnectStub::CallMethod [methodIndex=%hu]\n", aMethodIndex));
+
+ nsresult rv;
+
+ // reset the exception early. this is necessary because we may return a
+ // failure from here without setting an exception (which might be expected
+ // by the caller to detect the error origin: the interface we are stubbing
+ // may indicate in some way that it always sets the exception info on
+ // failure, therefore an "infoless" failure means the origin is RPC).
+ // besides that, resetting the excetion before every IPC call is exactly the
+ // same thing as Win32 RPC does, so doing this is useful for getting
+ // similarity in behaviors.
+
+ nsCOMPtr <nsIExceptionService> es;
+ es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED (rv))
+ return rv;
+ nsCOMPtr <nsIExceptionManager> em;
+ rv = es->GetCurrentExceptionManager (getter_AddRefs(em));
+ if (NS_FAILED (rv))
+ return rv;
+ rv = em->SetCurrentException(NULL);
+ if (NS_FAILED (rv))
+ return rv;
+
+ // ensure ipcDConnectService is not deleted before we finish
+ nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+ if (!dConnect)
+ return NS_ERROR_FAILURE;
+
+ // dump arguments
+
+ PRUint8 i, paramCount = aInfo->GetParamCount();
+
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name;
+ nsCOMPtr<nsIInterfaceInfo> iinfo;
+ GetInterfaceInfo(getter_AddRefs(iinfo));
+ iinfo->GetNameShared(&name);
+ LOG((" instance=0x%Lx {%s}\n", mInstance, name));
+ LOG((" name=%s\n", aInfo->GetName()));
+ LOG((" param-count=%u\n", (PRUint32) paramCount));
+ }
+#endif
+
+
+ ipcMessageWriter writer(16 * paramCount);
+
+ // INVOKE message header
+ DConnectInvoke invoke;
+ invoke.opcode_major = DCON_OP_INVOKE;
+ invoke.opcode_minor = 0;
+ invoke.flags = 0;
+ invoke.request_index = NewRequestIndex();
+ invoke.instance = mInstance;
+ invoke.method_index = aMethodIndex;
+
+ LOG((" request-index=%d\n", (PRUint32) invoke.request_index));
+
+ writer.PutBytes(&invoke, sizeof(invoke));
+
+ // list of wrappers that get created during parameter serialization. if we
+ // are unable to send the INVOKE message, then we'll clean these up.
+ nsVoidArray wrappers;
+
+ for (i=0; i<paramCount; ++i)
+ {
+ const nsXPTParamInfo &paramInfo = aInfo->GetParam(i);
+
+ if (paramInfo.IsIn() && !paramInfo.IsDipper())
+ {
+ const nsXPTType &type = paramInfo.GetType();
+
+ if (type.IsInterfacePointer())
+ {
+ nsID iid;
+ rv = dConnect->GetIIDForMethodParam(mIInfo, aInfo, paramInfo, type,
+ aMethodIndex, aParams, PR_FALSE, iid);
+ if (NS_SUCCEEDED(rv))
+ rv = dConnect->SerializeInterfaceParam(writer, mPeerID, iid,
+ (nsISupports *) aParams[i].val.p,
+ wrappers);
+ }
+ else
+ rv = SerializeParam(writer, type, aParams[i]);
+
+ AssertMsgBreak(NS_SUCCEEDED(rv), ("i=%d rv=%#x\n", i, rv));
+ }
+ else if ((paramInfo.IsOut() || paramInfo.IsRetval()) && !aParams[i].val.p)
+ {
+ // report error early if NULL pointer is passed as an output parameter
+ rv = NS_ERROR_NULL_POINTER;
+ AssertMsgFailedBreak(("i=%d IsOut=%d IsRetval=%d NS_ERROR_NULL_POINTER\n", i, paramInfo.IsOut(), paramInfo.IsRetval()));
+ break;
+ }
+ }
+
+ if (NS_FAILED(rv))
+ {
+ // INVOKE message wasn't sent; clean up wrappers
+ dConnect->ReleaseWrappers(wrappers, mPeerID);
+ return rv;
+ }
+
+ // serialize input array parameters after everything else since the
+ // deserialization procedure will need to get a size_is value which may be
+ // stored in any preceeding or following param
+ for (i=0; i<paramCount; ++i)
+ {
+ const nsXPTParamInfo &paramInfo = aInfo->GetParam(i);
+
+ if (paramInfo.GetType().IsArray() &&
+ paramInfo.IsIn() && !paramInfo.IsDipper())
+ {
+ rv = SerializeArrayParam(dConnect, writer, mPeerID, mIInfo, aMethodIndex,
+ *aInfo, aParams, PR_FALSE, paramInfo,
+ aParams[i].val.p, wrappers);
+ if (NS_FAILED(rv))
+ {
+ // INVOKE message wasn't sent; clean up wrappers
+ dConnect->ReleaseWrappers(wrappers, mPeerID);
+ return rv;
+ }
+ }
+ }
+
+ // temporarily disable the DConnect target observer to block normal processing
+ // of pending messages through the event queue.
+ IPC_DISABLE_MESSAGE_OBSERVER_FOR_SCOPE(kDConnectTargetID);
+
+ rv = IPC_SendMessage(mPeerID, kDConnectTargetID,
+ writer.GetBuffer(),
+ writer.GetSize());
+ LOG(("DConnectStub::CallMethod: IPC_SendMessage()=%08X\n", rv));
+ if (NS_FAILED(rv))
+ {
+ // INVOKE message wasn't delivered; clean up wrappers
+ dConnect->ReleaseWrappers(wrappers, mPeerID);
+ return rv;
+ }
+
+ // now, we wait for the method call to complete. during that time, it's
+ // possible that we'll receive other method call requests. we'll process
+ // those while waiting for out method call to complete. it's critical that
+ // we do so since those other method calls might need to complete before
+ // out method call can complete!
+
+ DConnectInvokeCompletion completion(mPeerID, &invoke);
+
+ do
+ {
+ rv = IPC_WaitMessage(IPC_SENDER_ANY, kDConnectTargetID,
+ &completion.GetSelector(), &completion,
+ DCON_WAIT_TIMEOUT);
+ LOG(("DConnectStub::CallMethod: IPC_WaitMessage()=%08X\n", rv));
+ if (NS_FAILED(rv))
+ {
+ // INVOKE message wasn't received; clean up wrappers
+ dConnect->ReleaseWrappers(wrappers, mPeerID);
+ return rv;
+ }
+ }
+ while (completion.IsPending());
+
+ ipcMessageReader reader(completion.Params(), completion.ParamsLen());
+
+ rv = completion.GetResult();
+ if (NS_SUCCEEDED(rv))
+ {
+ PRUint8 i;
+
+ // handle out-params and retvals: DCON_OP_INVOKE_REPLY has the data
+ for (i=0; i<paramCount; ++i)
+ {
+ const nsXPTParamInfo &paramInfo = aInfo->GetParam(i);
+
+ if (paramInfo.IsOut() || paramInfo.IsRetval())
+ DeserializeResult(reader, paramInfo.GetType(), aParams[i]);
+ }
+
+ // fixup any interface pointers using a second pass so we can properly
+ // handle INTERFACE_IS referencing an IID that is an out param! This pass is
+ // also used to deserialize arrays (array data goes after all other params).
+ for (i=0; i<paramCount && NS_SUCCEEDED(rv); ++i)
+ {
+ const nsXPTParamInfo &paramInfo = aInfo->GetParam(i);
+ if ((paramInfo.IsOut() || paramInfo.IsRetval()) && aParams[i].val.p)
+ {
+ const nsXPTType &type = paramInfo.GetType();
+ if (type.IsInterfacePointer())
+ {
+ // grab the DConAddr value temporarily stored in the param, restore
+ // the pointer and free the temporarily allocated memory.
+ DConAddrPlusPtr *dptr = (DConAddrPlusPtr *)aParams[i].val.p;
+ PtrBits bits = dptr->addr;
+ aParams[i].val.p = dptr->p;
+ nsMemory::Free((void *)dptr);
+
+ // DeserializeInterfaceParamBits needs IID only if it's a remote object
+ nsID iid;
+ if (bits & PTRBITS_REMOTE_BIT)
+ rv = dConnect->GetIIDForMethodParam(mIInfo, aInfo, paramInfo, type,
+ aMethodIndex, aParams, PR_FALSE,
+ iid);
+ if (NS_SUCCEEDED(rv))
+ {
+ nsISupports *obj = nsnull;
+ rv = dConnect->DeserializeInterfaceParamBits(bits, mPeerID, iid, obj);
+ if (NS_SUCCEEDED(rv))
+ *(void **)aParams[i].val.p = obj;
+ }
+ }
+ else if (type.IsArray())
+ {
+ void *array = nsnull;
+ rv = DeserializeArrayParam(dConnect, reader, mPeerID, mIInfo,
+ aMethodIndex, *aInfo, aParams, PR_FALSE,
+ paramInfo, PR_TRUE, array);
+ if (NS_SUCCEEDED(rv))
+ *(void **)aParams[i].val.p = array;
+ }
+ }
+ }
+ }
+
+ if (completion.Reply()->flags & DCON_OP_FLAGS_REPLY_EXCEPTION)
+ {
+ LOG(("got nsIException instance, will create a stub\n"));
+
+ nsIException *xcpt = nsnull;
+ rv = dConnect->DeserializeException (reader, mPeerID, &xcpt);
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = em->SetCurrentException(xcpt);
+ NS_IF_RELEASE(xcpt);
+ }
+ NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception");
+ }
+
+ return NS_SUCCEEDED(rv) ? completion.GetResult() : rv;
+}
+
+//-----------------------------------------------------------------------------
+
+class DConnectSetupCompletion : public DConnectCompletion
+{
+public:
+ DConnectSetupCompletion(PRUint32 peer, const DConnectSetup *setup)
+ : DConnectCompletion(peer, DCON_OP_SETUP_REPLY, setup->request_index)
+ , mSetup(setup)
+ , mStatus(NS_OK)
+ {}
+
+ void OnResponseAvailable(PRUint32 sender, const DConnectOp *op, PRUint32 opLen)
+ {
+ if (op->opcode_major != DCON_OP_SETUP_REPLY)
+ {
+ NS_NOTREACHED("unexpected response");
+ mStatus = NS_ERROR_UNEXPECTED;
+ return;
+ }
+
+ if (opLen < sizeof(DConnectSetupReply))
+ {
+ NS_NOTREACHED("unexpected response size");
+ mStatus = NS_ERROR_UNEXPECTED;
+ return;
+ }
+
+ const DConnectSetupReply *reply = (const DConnectSetupReply *) op;
+
+ LOG(("got SETUP_REPLY: status=%x instance=0x%Lx\n", reply->status, reply->instance));
+
+ mStatus = reply->status;
+
+ if (NS_SUCCEEDED(reply->status))
+ {
+ // ensure ipcDConnectService is not deleted before we finish
+ nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+ nsresult rv;
+ if (dConnect)
+ rv = dConnect->CreateStub(mSetup->iid, sender, reply->instance,
+ getter_AddRefs(mStub));
+ else
+ rv = NS_ERROR_FAILURE;
+ if (NS_FAILED(rv))
+ mStatus = rv;
+ }
+
+ if (reply->flags & DCON_OP_FLAGS_REPLY_EXCEPTION)
+ {
+ const PRUint8 *params = ((const PRUint8 *) op) + sizeof (DConnectSetupReply);
+ const PRUint32 paramsLen = opLen - sizeof (DConnectSetupReply);
+
+ ipcMessageReader reader(params, paramsLen);
+
+ LOG(("got nsIException instance, will create a stub\n"));
+
+ nsresult rv;
+ nsCOMPtr <nsIExceptionService> es;
+ es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr <nsIExceptionManager> em;
+ rv = es->GetCurrentExceptionManager (getter_AddRefs(em));
+ if (NS_SUCCEEDED(rv))
+ {
+ // ensure ipcDConnectService is not deleted before we finish
+ nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
+ if (dConnect)
+ {
+ nsIException *xcpt = nsnull;
+ rv = dConnect->DeserializeException (reader, sender, &xcpt);
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = em->SetCurrentException(xcpt);
+ NS_IF_RELEASE(xcpt);
+ }
+ }
+ else
+ rv = NS_ERROR_UNEXPECTED;
+ }
+ }
+ NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception");
+ if (NS_FAILED(rv))
+ mStatus = rv;
+ }
+ }
+
+ nsresult GetStub(void **aInstancePtr)
+ {
+ if (NS_FAILED(mStatus))
+ return mStatus;
+
+ DConnectStub *stub = mStub;
+ NS_IF_ADDREF(stub);
+ *aInstancePtr = stub;
+ return NS_OK;
+ }
+
+private:
+ const DConnectSetup *mSetup;
+ nsresult mStatus;
+ nsRefPtr<DConnectStub> mStub;
+};
+
+// static
+nsresult
+SetupPeerInstance(PRUint32 aPeerID, DConnectSetup *aMsg, PRUint32 aMsgLen,
+ void **aInstancePtr)
+{
+ *aInstancePtr = nsnull;
+
+ aMsg->opcode_major = DCON_OP_SETUP;
+ aMsg->flags = 0;
+ aMsg->request_index = NewRequestIndex();
+
+ // temporarily disable the DConnect target observer to block normal processing
+ // of pending messages through the event queue.
+ IPC_DISABLE_MESSAGE_OBSERVER_FOR_SCOPE(kDConnectTargetID);
+
+ // send SETUP message, expect SETUP_REPLY
+
+ nsresult rv = IPC_SendMessage(aPeerID, kDConnectTargetID,
+ (const PRUint8 *) aMsg, aMsgLen);
+ if (NS_FAILED(rv))
+ return rv;
+
+ DConnectSetupCompletion completion(aPeerID, aMsg);
+
+ // need to allow messages from other clients to be processed immediately
+ // to avoid distributed dead locks. the completion's OnMessageAvailable
+ // will call our default OnMessageAvailable if it receives any message
+ // other than the one for which it is waiting.
+
+ do
+ {
+ rv = IPC_WaitMessage(IPC_SENDER_ANY, kDConnectTargetID,
+ &completion.GetSelector(), &completion,
+ DCON_WAIT_TIMEOUT);
+ if (NS_FAILED(rv))
+ break;
+
+ rv = completion.GetStub(aInstancePtr);
+ }
+ while (NS_SUCCEEDED(rv) && *aInstancePtr == nsnull);
+
+ return rv;
+}
+
+//-----------------------------------------------------------------------------
+
+#if defined(DCONNECT_MULTITHREADED) && !defined(DCONNECT_WITH_IPRT_REQ_POOL)
+
+class DConnectWorker : public nsIRunnable
+{
+public:
+ // no reference counting
+ NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
+ NS_IMETHOD_(nsrefcnt) Release() { return 1; }
+ NS_IMETHOD QueryInterface(const nsIID &aIID, void **aInstancePtr);
+
+ NS_DECL_NSIRUNNABLE
+
+ DConnectWorker(ipcDConnectService *aDConnect) : mDConnect (aDConnect), mIsRunnable (PR_FALSE) {}
+ NS_HIDDEN_(nsresult) Init();
+ NS_HIDDEN_(void) Join() { mThread->Join(); };
+ NS_HIDDEN_(bool) IsRunning() { return mIsRunnable; };
+
+private:
+ nsCOMPtr <nsIThread> mThread;
+ ipcDConnectService *mDConnect;
+
+ // Indicate if thread might be quickly joined on shutdown.
+ volatile bool mIsRunnable;
+};
+
+NS_IMPL_QUERY_INTERFACE1(DConnectWorker, nsIRunnable)
+
+nsresult
+DConnectWorker::Init()
+{
+ return NS_NewThread(getter_AddRefs(mThread), this, 0, PR_JOINABLE_THREAD);
+}
+
+NS_IMETHODIMP
+DConnectWorker::Run()
+{
+ LOG(("DConnect Worker thread started.\n"));
+
+ mIsRunnable = PR_TRUE;
+
+ nsAutoMonitor mon(mDConnect->mPendingMon);
+
+ while (!mDConnect->mDisconnected)
+ {
+ DConnectRequest *request = mDConnect->mPendingQ.First();
+ if (!request)
+ {
+ mDConnect->mWaitingWorkers++;
+ {
+ // Note: we attempt to enter mWaitingWorkersMon from under mPendingMon
+ // here, but it should be safe because it's the only place where it
+ // happens. We could exit mPendingMon first, but we need to wait on it
+ // shorltly afterwards, which in turn will require us to enter it again
+ // just to exit immediately and start waiting. This seems to me a bit
+ // stupid (exit->enter->exit->wait).
+ nsAutoMonitor workersMon(mDConnect->mWaitingWorkersMon);
+ workersMon.NotifyAll();
+ }
+
+ nsresult rv = mon.Wait();
+ mDConnect->mWaitingWorkers--;
+
+ if (NS_FAILED(rv))
+ break;
+ }
+ else
+ {
+ LOG(("DConnect Worker thread got request.\n"));
+
+ // remove the request from the queue
+ mDConnect->mPendingQ.RemoveFirst();
+
+ PRBool pendingQEmpty = mDConnect->mPendingQ.IsEmpty();
+ mon.Exit();
+
+ if (pendingQEmpty)
+ {
+ nsAutoMonitor workersMon(mDConnect->mWaitingWorkersMon);
+ workersMon.NotifyAll();
+ }
+
+ // request is processed outside the queue monitor
+ mDConnect->OnIncomingRequest(request->peer, request->op, request->opLen);
+ delete request;
+
+ mon.Enter();
+ }
+ }
+
+ mIsRunnable = PR_FALSE;
+
+ LOG(("DConnect Worker thread stopped.\n"));
+ return NS_OK;
+}
+
+// called only on DConnect message thread
+nsresult
+ipcDConnectService::CreateWorker()
+{
+ DConnectWorker *worker = new DConnectWorker(this);
+ if (!worker)
+ return NS_ERROR_OUT_OF_MEMORY;
+ nsresult rv = worker->Init();
+ if (NS_SUCCEEDED(rv))
+ {
+ nsAutoLock lock(mLock);
+ /* tracking an illegal join in Shutdown. */
+ NS_ASSERTION(!mDisconnected, "CreateWorker racing Shutdown");
+ if (!mWorkers.AppendElement(worker))
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ }
+ if (NS_FAILED(rv))
+ delete worker;
+ return rv;
+}
+
+#endif // defined(DCONNECT_MULTITHREADED) && !defined(DCONNECT_WITH_IPRT_REQ_POOL)
+
+//-----------------------------------------------------------------------------
+
+ipcDConnectService::ipcDConnectService()
+ : mLock(NULL)
+ , mStubLock(NULL)
+ , mDisconnected(PR_TRUE)
+ , mStubQILock(NULL)
+#if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+ , mhReqPool(NIL_RTREQPOOL)
+#endif
+{
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+EnumerateInstanceMapAndDelete (const DConnectInstanceKey::Key &aKey,
+ DConnectInstance *aData,
+ void *userArg)
+{
+ // this method is to be called on ipcDConnectService shutdown only
+ // (after which no DConnectInstances may exist), so forcibly delete them
+ // disregarding the reference counter
+
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name;
+ aData->InterfaceInfo()->GetNameShared(&name);
+ LOG(("ipcDConnectService: WARNING: deleting unreleased "
+ "instance=%p iface=%p {%s}\n", aData, aData->RealInstance(), name));
+ }
+#endif
+
+ delete aData;
+ return PL_DHASH_NEXT;
+}
+
+ipcDConnectService::~ipcDConnectService()
+{
+ if (!mDisconnected)
+ Shutdown();
+
+ mInstance = nsnull;
+ PR_DestroyLock(mStubQILock);
+ PR_DestroyLock(mStubLock);
+ PR_DestroyLock(mLock);
+#if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+ RTReqPoolRelease(mhReqPool);
+ mhReqPool = NIL_RTREQPOOL;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+
+nsresult
+ipcDConnectService::Init()
+{
+ nsresult rv;
+
+ LOG(("ipcDConnectService::Init.\n"));
+
+ rv = IPC_DefineTarget(kDConnectTargetID, this);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = IPC_AddClientObserver(this);
+ if (NS_FAILED(rv))
+ return rv;
+
+ mLock = PR_NewLock();
+ if (!mLock)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ if (!mInstances.Init())
+ return NS_ERROR_OUT_OF_MEMORY;
+ if (!mInstanceSet.Init())
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ mStubLock = PR_NewLock();
+ if (!mStubLock)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ if (!mStubs.Init())
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ mIIM = do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ mStubQILock = PR_NewLock();
+ if (!mStubQILock)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+#if defined(DCONNECT_MULTITHREADED)
+# if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+ int vrc = RTReqPoolCreate(1024 /*cMaxThreads*/, 10*RT_MS_1SEC /*cMsMinIdle*/,
+ 8 /*cThreadsPushBackThreshold */, RT_MS_1SEC /* cMsMaxPushBack */,
+ "DCon", &mhReqPool);
+ if (RT_FAILURE(vrc))
+ {
+ mhReqPool = NIL_RTREQPOOL;
+ return NS_ERROR_FAILURE;
+ }
+
+ mDisconnected = PR_FALSE;
+
+# else
+
+ mPendingMon = nsAutoMonitor::NewMonitor("DConnect pendingQ monitor");
+ if (!mPendingMon)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ mWaitingWorkers = 0;
+
+ mWaitingWorkersMon = nsAutoMonitor::NewMonitor("DConnect waiting workers monitor");
+ if (!mWaitingWorkersMon)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ /* The DConnectWorker::Run method checks the ipcDConnectService::mDisconnected.
+ * So mDisconnect must be set here to avoid an immediate exit of the worker thread.
+ */
+ mDisconnected = PR_FALSE;
+
+ // create a single worker thread
+ rv = CreateWorker();
+ if (NS_FAILED(rv))
+ {
+ mDisconnected = PR_TRUE;
+ return rv;
+ }
+
+# endif
+#else
+
+ mDisconnected = PR_FALSE;
+
+#endif
+
+ mInstance = this;
+
+ LOG(("ipcDConnectService::Init NS_OK.\n"));
+ return NS_OK;
+}
+
+void
+ipcDConnectService::Shutdown()
+{
+ {
+ // set the disconnected flag to make sensitive public methods
+ // unavailale from other (non worker) threads.
+ nsAutoLock lock(mLock);
+ mDisconnected = PR_TRUE;
+ }
+
+#if defined(DCONNECT_MULTITHREADED)
+# if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+
+# if defined(DCONNECT_STATS)
+ fprintf(stderr, "ipcDConnectService Stats\n");
+ fprintf(stderr,
+ " => number of worker threads: %llu (created %llu)\n"
+ " => requests processed: %llu\n"
+ " => avg requests process time: %llu ns\n"
+ " => avg requests waiting time: %llu ns\n",
+ RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_THREADS),
+ RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_THREADS_CREATED),
+ RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_REQUESTS_PROCESSED),
+ RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_NS_AVERAGE_REQ_PROCESSING),
+ RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_NS_AVERAGE_REQ_QUEUED)
+ );
+# endif
+
+ RTReqPoolRelease(mhReqPool);
+ mhReqPool = NIL_RTREQPOOL;
+
+# else
+
+ {
+ // remove all pending messages and wake up all workers.
+ // mDisconnected is true here and they will terminate execution after
+ // processing the last request.
+ nsAutoMonitor mon(mPendingMon);
+ mPendingQ.DeleteAll();
+ mon.NotifyAll();
+ }
+
+#if defined(DCONNECT_STATS)
+ fprintf(stderr, "ipcDConnectService Stats\n");
+ fprintf(stderr, " => number of worker threads: %d\n", mWorkers.Count());
+ LOG(("ipcDConnectService Stats\n"));
+ LOG((" => number of worker threads: %d\n", mWorkers.Count()));
+#endif
+
+
+ // Iterate over currently running worker threads
+ // during VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS, join() those who
+ // exited a working loop and abandon ones which have not
+ // managed to do that when timeout occurred.
+ LOG(("Worker threads: %d\n", mWorkers.Count()));
+ uint64_t tsStart = RTTimeMilliTS();
+ while ((tsStart + VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS ) > RTTimeMilliTS() && mWorkers.Count() > 0)
+ {
+ // Some array elements might be deleted while iterating. Going from the last
+ // to the first array element (intentionally) in order to do not conflict with
+ // array indexing once element is deleted.
+ for (int i = mWorkers.Count() - 1; i >= 0; i--)
+ {
+ DConnectWorker *worker = NS_STATIC_CAST(DConnectWorker *, mWorkers[i]);
+ if (worker->IsRunning() == PR_FALSE)
+ {
+ LOG(("Worker %p joined.\n", worker));
+ worker->Join();
+ delete worker;
+ mWorkers.RemoveElementAt(i);
+ }
+ }
+
+ /* Double-ckeck if we already allowed to quit. */
+ if ((tsStart + VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS ) < RTTimeMilliTS() || mWorkers.Count() == 0)
+ break;
+
+ // Relax a bit before the next round.
+ RTThreadSleep(10);
+ }
+
+ LOG(("There are %d thread(s) left.\n", mWorkers.Count()));
+
+ // If there are some running threads left, terminate the process.
+ if (mWorkers.Count() > 0)
+ exit(1);
+
+
+ nsAutoMonitor::DestroyMonitor(mWaitingWorkersMon);
+ nsAutoMonitor::DestroyMonitor(mPendingMon);
+
+# endif
+#endif
+
+ // make sure we have released all instances
+ mInstances.EnumerateRead(EnumerateInstanceMapAndDelete, nsnull);
+
+ mInstanceSet.Clear();
+ mInstances.Clear();
+
+ // clear the stub table
+ // (this will not release stubs -- it's the client's responsibility)
+ mStubs.Clear();
+}
+
+// this should be inlined
+nsresult
+ipcDConnectService::GetInterfaceInfo(const nsID &iid, nsIInterfaceInfo **result)
+{
+ return mIIM->GetInfoForIID(&iid, result);
+}
+
+// this is adapted from the version in xpcwrappednative.cpp
+nsresult
+ipcDConnectService::GetIIDForMethodParam(nsIInterfaceInfo *iinfo,
+ const nsXPTMethodInfo *methodInfo,
+ const nsXPTParamInfo &paramInfo,
+ const nsXPTType &type,
+ PRUint16 methodIndex,
+ nsXPTCMiniVariant *dispatchParams,
+ PRBool isXPTCVariantArray,
+ nsID &result)
+{
+ PRUint8 argnum, tag = type.TagPart();
+ nsresult rv;
+
+ if (tag == nsXPTType::T_INTERFACE)
+ {
+ rv = iinfo->GetIIDForParamNoAlloc(methodIndex, &paramInfo, &result);
+ }
+ else if (tag == nsXPTType::T_INTERFACE_IS)
+ {
+ rv = iinfo->GetInterfaceIsArgNumberForParam(methodIndex, &paramInfo, &argnum);
+ if (NS_FAILED(rv))
+ return rv;
+
+ const nsXPTParamInfo& arg_param = methodInfo->GetParam(argnum);
+ const nsXPTType& arg_type = arg_param.GetType();
+
+ // The xpidl compiler ensures this. We reaffirm it for safety.
+ if (!arg_type.IsPointer() || arg_type.TagPart() != nsXPTType::T_IID)
+ return NS_ERROR_UNEXPECTED;
+
+ nsID *p = (nsID *) GET_PARAM(dispatchParams, isXPTCVariantArray, argnum).val.p;
+ if (!p)
+ return NS_ERROR_UNEXPECTED;
+
+ result = *p;
+ }
+ else
+ rv = NS_ERROR_UNEXPECTED;
+ return rv;
+}
+
+nsresult
+ipcDConnectService::StoreInstance(DConnectInstance *wrapper)
+{
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name;
+ wrapper->InterfaceInfo()->GetNameShared(&name);
+ LOG(("ipcDConnectService::StoreInstance(): instance=%p iface=%p {%s}\n",
+ wrapper, wrapper->RealInstance(), name));
+ }
+#endif
+
+ nsresult rv = mInstanceSet.Put(wrapper);
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = mInstances.Put(wrapper->GetKey(), wrapper)
+ ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+ if (NS_FAILED(rv))
+ mInstanceSet.Remove(wrapper);
+ }
+ return rv;
+}
+
+void
+ipcDConnectService::DeleteInstance(DConnectInstance *wrapper,
+ PRBool locked /* = PR_FALSE */)
+{
+ if (!locked)
+ PR_Lock(mLock);
+
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name;
+ wrapper->InterfaceInfo()->GetNameShared(&name);
+ LOG(("ipcDConnectService::DeleteInstance(): instance=%p iface=%p {%s}\n",
+ wrapper, wrapper->RealInstance(), name));
+ }
+#endif
+
+ mInstances.Remove(wrapper->GetKey());
+ mInstanceSet.Remove(wrapper);
+
+ if (!locked)
+ PR_Unlock(mLock);
+}
+
+PRBool
+ipcDConnectService::FindInstanceAndAddRef(PRUint32 peer,
+ const nsISupports *obj,
+ const nsIID *iid,
+ DConnectInstance **wrapper)
+{
+ PRBool result = mInstances.Get(DConnectInstanceKey::Key(peer, obj, iid), wrapper);
+ if (result)
+ (*wrapper)->AddRef();
+ return result;
+}
+
+PRBool
+ipcDConnectService::CheckInstanceAndAddRef(DConnectInstance *wrapper, PRUint32 peer)
+{
+ nsAutoLock lock (mLock);
+
+ if (mInstanceSet.Contains(wrapper) && wrapper->Peer() == peer)
+ {
+ wrapper->AddRef();
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+nsresult
+ipcDConnectService::StoreStub(DConnectStub *stub)
+{
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name;
+ nsCOMPtr<nsIInterfaceInfo> iinfo;
+ stub->GetInterfaceInfo(getter_AddRefs(iinfo));
+ iinfo->GetNameShared(&name);
+ LOG(("ipcDConnectService::StoreStub(): stub=%p instance=0x%Lx {%s}\n",
+ stub, stub->Instance(), name));
+ }
+#endif
+
+ return mStubs.Put(stub->GetKey(), stub)
+ ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+void
+ipcDConnectService::DeleteStub(DConnectStub *stub)
+{
+#ifdef IPC_LOGGING
+ if (IPC_LOG_ENABLED())
+ {
+ const char *name;
+ nsCOMPtr<nsIInterfaceInfo> iinfo;
+ stub->GetInterfaceInfo(getter_AddRefs(iinfo));
+ iinfo->GetNameShared(&name);
+ LOG(("ipcDConnectService::DeleteStub(): stub=%p instance=0x%Lx {%s}\n",
+ stub, stub->Instance(), name));
+ }
+#endif
+
+ // this method is intended to be called only from DConnectStub::Release().
+ // the stub object is not deleted when removed from the table, because
+ // DConnectStub pointers are not owned by mStubs.
+ mStubs.Remove(stub->GetKey());
+}
+
+// not currently used
+#if 0
+PRBool
+ipcDConnectService::FindStubAndAddRef(PRUint32 peer, const DConAddr instance,
+ DConnectStub **stub)
+{
+ nsAutoLock stubLock (mStubLock);
+
+ PRBool result = mStubs.Get(DConnectStubKey::Key(peer, instance), stub);
+ if (result)
+ NS_ADDREF(*stub);
+ return result;
+}
+#endif
+
+NS_IMPL_THREADSAFE_ISUPPORTS3(ipcDConnectService, ipcIDConnectService,
+ ipcIMessageObserver,
+ ipcIClientObserver)
+
+NS_IMETHODIMP
+ipcDConnectService::CreateInstance(PRUint32 aPeerID,
+ const nsID &aCID,
+ const nsID &aIID,
+ void **aInstancePtr)
+{
+ DConnectSetupClassID msg;
+ msg.opcode_minor = DCON_OP_SETUP_NEW_INST_CLASSID;
+ msg.iid = aIID;
+ msg.classid = aCID;
+
+ return SetupPeerInstance(aPeerID, &msg, sizeof(msg), aInstancePtr);
+}
+
+NS_IMETHODIMP
+ipcDConnectService::CreateInstanceByContractID(PRUint32 aPeerID,
+ const char *aContractID,
+ const nsID &aIID,
+ void **aInstancePtr)
+{
+ size_t slen = strlen(aContractID);
+ size_t size = sizeof(DConnectSetupContractID) + slen;
+
+ DConnectSetupContractID *msg =
+ (DConnectSetupContractID *) malloc(size);
+
+ msg->opcode_minor = DCON_OP_SETUP_NEW_INST_CONTRACTID;
+ msg->iid = aIID;
+ memcpy(&msg->contractid, aContractID, slen + 1);
+
+ nsresult rv = SetupPeerInstance(aPeerID, msg, size, aInstancePtr);
+
+ free(msg);
+ return rv;
+}
+
+NS_IMETHODIMP
+ipcDConnectService::GetService(PRUint32 aPeerID,
+ const nsID &aCID,
+ const nsID &aIID,
+ void **aInstancePtr)
+{
+ DConnectSetupClassID msg;
+ msg.opcode_minor = DCON_OP_SETUP_GET_SERV_CLASSID;
+ msg.iid = aIID;
+ msg.classid = aCID;
+
+ return SetupPeerInstance(aPeerID, &msg, sizeof(msg), aInstancePtr);
+}
+
+NS_IMETHODIMP
+ipcDConnectService::GetServiceByContractID(PRUint32 aPeerID,
+ const char *aContractID,
+ const nsID &aIID,
+ void **aInstancePtr)
+{
+ size_t slen = strlen(aContractID);
+ size_t size = sizeof(DConnectSetupContractID) + slen;
+
+ DConnectSetupContractID *msg =
+ (DConnectSetupContractID *) malloc(size);
+
+ msg->opcode_minor = DCON_OP_SETUP_GET_SERV_CONTRACTID;
+ msg->iid = aIID;
+ memcpy(&msg->contractid, aContractID, slen + 1);
+
+ nsresult rv = SetupPeerInstance(aPeerID, msg, size, aInstancePtr);
+
+ free(msg);
+ return rv;
+}
+
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+ipcDConnectService::OnMessageAvailable(PRUint32 aSenderID,
+ const nsID &aTarget,
+ const PRUint8 *aData,
+ PRUint32 aDataLen)
+{
+ if (mDisconnected)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ const DConnectOp *op = (const DConnectOp *) aData;
+
+ LOG (("ipcDConnectService::OnMessageAvailable: "
+ "senderID=%d, opcode_major=%d, index=%d\n",
+ aSenderID, op->opcode_major, op->request_index));
+
+#if defined(DCONNECT_MULTITHREADED)
+# if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+
+ void *pvDataDup = RTMemDup(aData, aDataLen);
+ if (RT_UNLIKELY(!pvDataDup))
+ return NS_ERROR_OUT_OF_MEMORY;
+ int rc = RTReqPoolCallVoidNoWait(mhReqPool, (PFNRT)ProcessMessageOnWorkerThread, 4,
+ this, aSenderID, pvDataDup, aDataLen);
+ if (RT_FAILURE(rc))
+ return NS_ERROR_FAILURE;
+
+# else
+
+ nsAutoMonitor mon(mPendingMon);
+ mPendingQ.Append(new DConnectRequest(aSenderID, op, aDataLen));
+ // notify a worker
+ mon.Notify();
+ mon.Exit();
+
+ // Yield the cpu so a worker can get a chance to start working without too much fuss.
+ PR_Sleep(PR_INTERVAL_NO_WAIT);
+ mon.Enter();
+ // examine the queue
+ if (mPendingQ.Count() > mWaitingWorkers)
+ {
+ // wait a little while to let the workers empty the queue.
+ mon.Exit();
+ {
+ PRUint32 ticks = PR_MillisecondsToInterval(PR_MIN(mWorkers.Count() / 20 + 1, 10));
+ nsAutoMonitor workersMon(mWaitingWorkersMon);
+ workersMon.Wait(ticks);
+ }
+ mon.Enter();
+ // examine the queue again
+ if (mPendingQ.Count() > mWaitingWorkers)
+ {
+ // we need one more worker
+ nsresult rv = CreateWorker();
+ NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create one more worker thread");
+ rv = rv;
+ }
+ }
+
+# endif
+#else
+
+ OnIncomingRequest(aSenderID, op, aDataLen);
+
+#endif
+
+ return NS_OK;
+}
+
+struct PruneInstanceMapForPeerArgs
+{
+ ipcDConnectService *that;
+ PRUint32 clientID;
+ nsVoidArray &wrappers;
+};
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+PruneInstanceMapForPeer (const DConnectInstanceKey::Key &aKey,
+ DConnectInstance *aData,
+ void *userArg)
+{
+ PruneInstanceMapForPeerArgs *args = (PruneInstanceMapForPeerArgs *)userArg;
+ NS_ASSERTION(args, "PruneInstanceMapForPeerArgs is NULL");
+
+ if (args && args->clientID == aData->Peer())
+ {
+ nsrefcnt countIPC = aData->ReleaseIPC(PR_TRUE /* locked */);
+
+ LOG(("ipcDConnectService::PruneInstanceMapForPeer: "
+ "instance=%p: %d IPC refs to release\n",
+ aData, countIPC + 1));
+
+ // release all IPC instances of the "officially dead" client (see
+ // #OnRelease() to understand why it must be done under the lock). Note
+ // that due to true multithreading, late OnRelease() requests may still
+ // happen on other worker threads *after* OnClientStateChange() has been
+ // called, but it's OK because the instance will be removed from the map
+ // by the below code alreay and won't be deleted for the second time.
+ while (countIPC)
+ {
+ countIPC = aData->ReleaseIPC(PR_TRUE /* locked */);
+ aData->Release();
+ }
+
+ // collect the instance for the last release
+ // (we'll do it later outside the lock)
+ if (!args->wrappers.AppendElement(aData))
+ {
+ NS_NOTREACHED("Not enough memory");
+ // bad but what to do
+ aData->Release();
+ }
+ }
+ return PL_DHASH_NEXT;
+}
+
+NS_IMETHODIMP
+ipcDConnectService::OnClientStateChange(PRUint32 aClientID,
+ PRUint32 aClientState)
+{
+ LOG(("ipcDConnectService::OnClientStateChange: aClientID=%d, aClientState=%d\n",
+ aClientID, aClientState));
+
+ if (aClientState == ipcIClientObserver::CLIENT_DOWN)
+ {
+ if (aClientID == IPC_SENDER_ANY)
+ {
+ // a special case: our IPC system is being shutdown, try to safely
+ // uninitialize everything...
+ Shutdown();
+ }
+ else
+ {
+ LOG(("ipcDConnectService::OnClientStateChange: "
+ "pruning all instances created for peer %d...\n", aClientID));
+
+ nsVoidArray wrappers;
+
+ {
+ nsAutoLock lock (mLock);
+
+ // make sure we have removed all instances from instance maps
+ PruneInstanceMapForPeerArgs args = { this, aClientID, wrappers };
+ mInstances.EnumerateRead(PruneInstanceMapForPeer, (void *)&args);
+ }
+
+ LOG(("ipcDConnectService::OnClientStateChange: "
+ "%d lost instances\n", wrappers.Count()));
+
+ // release all pending references left after PruneInstanceMapForPeer().
+ // this may call wrapper destructors so it's important to do that
+ // outside the lock because destructors will release the real objects
+ // which may need to make asynchronous use our service
+ for (PRInt32 i = 0; i < wrappers.Count(); ++i)
+ ((DConnectInstance *) wrappers[i])->Release();
+ }
+ }
+
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+
+#if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+/**
+ * Function called by the request thread pool to process a incoming request in
+ * the context of a worker thread.
+ */
+/* static */ DECLCALLBACK(void)
+ipcDConnectService::ProcessMessageOnWorkerThread(ipcDConnectService *aThis, PRUint32 aSenderID, void *aData, PRUint32 aDataLen)
+{
+ if (!aThis->mDisconnected)
+ aThis->OnIncomingRequest(aSenderID, (const DConnectOp *)aData, aDataLen);
+ RTMemFree(aData);
+}
+#endif
+
+void
+ipcDConnectService::OnIncomingRequest(PRUint32 peer, const DConnectOp *op, PRUint32 opLen)
+{
+ switch (op->opcode_major)
+ {
+ case DCON_OP_SETUP:
+ OnSetup(peer, (const DConnectSetup *) op, opLen);
+ break;
+ case DCON_OP_RELEASE:
+ OnRelease(peer, (const DConnectRelease *) op);
+ break;
+ case DCON_OP_INVOKE:
+ OnInvoke(peer, (const DConnectInvoke *) op, opLen);
+ break;
+ default:
+ NS_NOTREACHED("unknown opcode major");
+ }
+}
+
+void
+ipcDConnectService::OnSetup(PRUint32 peer, const DConnectSetup *setup, PRUint32 opLen)
+{
+ nsISupports *instance = nsnull;
+ nsresult rv = NS_ERROR_FAILURE;
+
+ switch (setup->opcode_minor)
+ {
+ // CreateInstance
+ case DCON_OP_SETUP_NEW_INST_CLASSID:
+ {
+ const DConnectSetupClassID *setupCI = (const DConnectSetupClassID *) setup;
+
+ nsCOMPtr<nsIComponentManager> compMgr;
+ rv = NS_GetComponentManager(getter_AddRefs(compMgr));
+ if (NS_SUCCEEDED(rv))
+ rv = compMgr->CreateInstance(setupCI->classid, nsnull, setupCI->iid, (void **) &instance);
+
+ break;
+ }
+
+ // CreateInstanceByContractID
+ case DCON_OP_SETUP_NEW_INST_CONTRACTID:
+ {
+ const DConnectSetupContractID *setupCI = (const DConnectSetupContractID *) setup;
+
+ nsCOMPtr<nsIComponentManager> compMgr;
+ rv = NS_GetComponentManager(getter_AddRefs(compMgr));
+ if (NS_SUCCEEDED(rv))
+ rv = compMgr->CreateInstanceByContractID(setupCI->contractid, nsnull, setupCI->iid, (void **) &instance);
+
+ break;
+ }
+
+ // GetService
+ case DCON_OP_SETUP_GET_SERV_CLASSID:
+ {
+ const DConnectSetupClassID *setupCI = (const DConnectSetupClassID *) setup;
+
+ nsCOMPtr<nsIServiceManager> svcMgr;
+ rv = NS_GetServiceManager(getter_AddRefs(svcMgr));
+ if (NS_SUCCEEDED(rv))
+ rv = svcMgr->GetService(setupCI->classid, setupCI->iid, (void **) &instance);
+ break;
+ }
+
+ // GetServiceByContractID
+ case DCON_OP_SETUP_GET_SERV_CONTRACTID:
+ {
+ const DConnectSetupContractID *setupCI = (const DConnectSetupContractID *) setup;
+
+ nsCOMPtr<nsIServiceManager> svcMgr;
+ rv = NS_GetServiceManager(getter_AddRefs(svcMgr));
+ if (NS_SUCCEEDED(rv))
+ rv = svcMgr->GetServiceByContractID(setupCI->contractid, setupCI->iid, (void **) &instance);
+
+ break;
+ }
+
+ // QueryInterface
+ case DCON_OP_SETUP_QUERY_INTERFACE:
+ {
+ const DConnectSetupQueryInterface *setupQI = (const DConnectSetupQueryInterface *) setup;
+ DConnectInstance *QIinstance = (DConnectInstance *)setupQI->instance;
+
+ // make sure we've been sent a valid wrapper
+ if (!CheckInstanceAndAddRef(QIinstance, peer))
+ {
+ NS_NOTREACHED("instance wrapper not found");
+ rv = NS_ERROR_INVALID_ARG;
+ }
+ else
+ {
+ rv = QIinstance->RealInstance()->QueryInterface(setupQI->iid, (void **) &instance);
+ QIinstance->Release();
+ }
+ break;
+ }
+
+ default:
+ NS_NOTREACHED("unexpected minor opcode");
+ rv = NS_ERROR_UNEXPECTED;
+ break;
+ }
+
+ nsVoidArray wrappers;
+
+ // now, create instance wrapper, and store it in our instances set.
+ // this allows us to keep track of object references held on behalf of a
+ // particular peer. we can use this information to cleanup after a peer
+ // that disconnects without sending RELEASE messages for its objects.
+ DConnectInstance *wrapper = nsnull;
+ if (NS_SUCCEEDED(rv))
+ {
+ nsCOMPtr<nsIInterfaceInfo> iinfo;
+ rv = GetInterfaceInfo(setup->iid, getter_AddRefs(iinfo));
+ if (NS_SUCCEEDED(rv))
+ {
+ nsAutoLock lock (mLock);
+
+ // first try to find an existing wrapper for the given object
+ if (!FindInstanceAndAddRef(peer, instance, &setup->iid, &wrapper))
+ {
+ wrapper = new DConnectInstance(peer, iinfo, instance);
+ if (!wrapper)
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ else
+ {
+ rv = StoreInstance(wrapper);
+ if (NS_FAILED(rv))
+ {
+ delete wrapper;
+ wrapper = nsnull;
+ }
+ else
+ {
+ // reference the newly created wrapper
+ wrapper->AddRef();
+ }
+ }
+ }
+
+ if (wrapper)
+ {
+ // increase the second, IPC-only, reference counter (mandatory before
+ // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove
+ // the wrapper from the instance map on failure)
+ wrapper->AddRefIPC();
+
+ if (!wrappers.AppendElement(wrapper))
+ {
+ wrapper->ReleaseIPC();
+ wrapper->Release();
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ // wrapper remains referenced when passing it to the client
+ // (will be released upon DCON_OP_RELEASE)
+ }
+ }
+
+ NS_IF_RELEASE(instance);
+
+ nsCOMPtr <nsIException> exception;
+ PRBool got_exception = PR_FALSE;
+
+ if (rv != NS_OK)
+ {
+ // try to fetch an nsIException possibly set by one of the setup methods
+ nsresult rv2;
+ nsCOMPtr <nsIExceptionService> es;
+ es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv2);
+ if (NS_SUCCEEDED(rv2))
+ {
+ nsCOMPtr <nsIExceptionManager> em;
+ rv2 = es->GetCurrentExceptionManager (getter_AddRefs (em));
+ if (NS_SUCCEEDED(rv2))
+ {
+ rv2 = em->GetCurrentException (getter_AddRefs (exception));
+ if (NS_SUCCEEDED(rv2))
+ {
+ LOG(("got nsIException instance, will serialize\n"));
+ got_exception = PR_TRUE;
+ }
+ }
+ }
+ NS_ASSERTION(NS_SUCCEEDED(rv2), "failed to get/serialize exception");
+ if (NS_FAILED(rv2))
+ rv = rv2;
+ }
+
+ ipcMessageWriter writer(64);
+
+ DConnectSetupReply msg;
+ msg.opcode_major = DCON_OP_SETUP_REPLY;
+ msg.opcode_minor = 0;
+ msg.flags = 0;
+ msg.request_index = setup->request_index;
+ msg.instance = (DConAddr)(uintptr_t)wrapper;
+ msg.status = rv;
+
+ if (got_exception)
+ msg.flags |= DCON_OP_FLAGS_REPLY_EXCEPTION;
+
+ writer.PutBytes(&msg, sizeof(msg));
+
+ if (got_exception)
+ {
+ rv = SerializeException(writer, peer, exception, wrappers);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialize exception");
+ }
+
+ // fire off SETUP_REPLY, don't wait for a response
+ if (NS_FAILED(rv))
+ rv = IPC_SendMessage(peer, kDConnectTargetID,
+ (const PRUint8 *) &msg, sizeof(msg));
+ else
+ rv = IPC_SendMessage(peer, kDConnectTargetID,
+ writer.GetBuffer(), writer.GetSize());
+
+ if (NS_FAILED(rv))
+ {
+ LOG(("unable to send SETUP_REPLY: rv=%x\n", rv));
+ ReleaseWrappers(wrappers, peer);
+ }
+}
+
+void
+ipcDConnectService::OnRelease(PRUint32 peer, const DConnectRelease *release)
+{
+ LOG(("ipcDConnectService::OnRelease [peer=%u instance=0x%Lx]\n",
+ peer, release->instance));
+
+ DConnectInstance *wrapper = (DConnectInstance *)release->instance;
+
+ nsAutoLock lock (mLock);
+
+ // make sure we've been sent a valid wrapper from the same peer we created
+ // this wrapper for
+ if (mInstanceSet.Contains(wrapper) && wrapper->Peer() == peer)
+ {
+ // release the IPC reference from under the lock to ensure atomicity of
+ // the "check + possible delete" sequence ("delete" is remove this wrapper
+ // from the instance map when the IPC reference counter drops to zero)
+ wrapper->ReleaseIPC(PR_TRUE /* locked */);
+ // leave the lock before Release() because it may call the destructor
+ // which will release the real object which may need to make asynchronous
+ // use our service
+ lock.unlock();
+ wrapper->Release();
+ }
+ else
+ {
+ // it is possible that the client disconnection event handler has released
+ // all client instances before the DCON_OP_RELEASE message sent by the
+ // client gets processed here (because of true multithreading). Just log
+ // a debug warning
+ LOG(("ipcDConnectService::OnRelease: WARNING: "
+ "instance wrapper %p for peer %d not found", wrapper, peer));
+ }
+}
+
+void
+ipcDConnectService::OnInvoke(PRUint32 peer, const DConnectInvoke *invoke, PRUint32 opLen)
+{
+ LOG(("ipcDConnectService::OnInvoke [peer=%u instance=0x%Lx method=%u]\n",
+ peer, invoke->instance, invoke->method_index));
+
+ DConnectInstance *wrapper = (DConnectInstance *)invoke->instance;
+
+ ipcMessageReader reader((const PRUint8 *) (invoke + 1), opLen - sizeof(*invoke));
+
+ const nsXPTMethodInfo *methodInfo;
+ nsXPTCVariant *params = nsnull;
+ nsCOMPtr<nsIInterfaceInfo> iinfo = nsnull;
+ PRUint8 i, paramCount = 0, paramUsed = 0;
+ nsresult rv;
+
+ nsCOMPtr <nsIException> exception;
+ PRBool got_exception = PR_FALSE;
+
+ // make sure we've been sent a valid wrapper
+ if (!CheckInstanceAndAddRef(wrapper, peer))
+ {
+ NS_NOTREACHED("instance wrapper not found");
+ wrapper = nsnull;
+ rv = NS_ERROR_INVALID_ARG;
+ goto end;
+ }
+
+ iinfo = wrapper->InterfaceInfo();
+
+ rv = iinfo->GetMethodInfo(invoke->method_index, &methodInfo);
+ if (NS_FAILED(rv))
+ goto end;
+
+ paramCount = methodInfo->GetParamCount();
+
+ LOG((" iface=%p\n", wrapper->RealInstance()));
+ LOG((" name=%s\n", methodInfo->GetName()));
+ LOG((" param-count=%u\n", (PRUint32) paramCount));
+ LOG((" request-index=%d\n", (PRUint32) invoke->request_index));
+
+ params = new nsXPTCVariant[paramCount];
+ if (!params)
+ {
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ goto end;
+ }
+
+ // setup |params| for xptcall
+
+ for (i=0; i<paramCount; ++i, ++paramUsed)
+ {
+ const nsXPTParamInfo &paramInfo = methodInfo->GetParam(i);
+
+ // XXX are inout params an issue?
+ // yes, we will need to do v.ptr = &v.val for them (DeserializeParam doesn't
+ // currently do that) to let the callee correctly pick it up and change.
+
+ if (paramInfo.IsIn() && !paramInfo.IsDipper())
+ rv = DeserializeParam(reader, paramInfo.GetType(), params[i]);
+ else
+ rv = SetupParam(paramInfo, params[i]);
+
+ if (NS_FAILED(rv))
+ goto end;
+ }
+
+ // fixup any interface pointers. we do this with a second pass so that
+ // we can properly handle INTERFACE_IS. This pass is also used to deserialize
+ // arrays (array data goes after all other params).
+ for (i=0; i<paramCount; ++i)
+ {
+ const nsXPTParamInfo &paramInfo = methodInfo->GetParam(i);
+ if (paramInfo.IsIn())
+ {
+ const nsXPTType &type = paramInfo.GetType();
+ if (type.IsInterfacePointer())
+ {
+ // grab the DConAddr value temporarily stored in the param
+#ifdef VBOX
+ PtrBits bits = params[i].val.u64;
+#else
+ PtrBits bits = (PtrBits)(uintptr_t) params[i].val.p;
+#endif
+
+ // DeserializeInterfaceParamBits needs IID only if it's a remote object
+ nsID iid;
+ if (bits & PTRBITS_REMOTE_BIT)
+ {
+ rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, type,
+ invoke->method_index, params, PR_TRUE, iid);
+ if (NS_FAILED(rv))
+ goto end;
+ }
+
+ nsISupports *obj = nsnull;
+ rv = DeserializeInterfaceParamBits(bits, peer, iid, obj);
+ if (NS_FAILED(rv))
+ goto end;
+
+ params[i].val.p = obj;
+ // mark as interface to let FinishParam() release this param
+ params[i].SetValIsInterface();
+ }
+ else if (type.IsArray())
+ {
+ void *array = nsnull;
+ rv = DeserializeArrayParam(this, reader, peer, iinfo,
+ invoke->method_index, *methodInfo, params,
+ PR_TRUE, paramInfo, PR_FALSE, array);
+ if (NS_FAILED(rv))
+ goto end;
+
+ params[i].val.p = array;
+ // mark to let FinishParam() free this param
+ params[i].SetValIsAllocated();
+ }
+ }
+ }
+
+ rv = XPTC_InvokeByIndex(wrapper->RealInstance(),
+ invoke->method_index,
+ paramCount,
+ params);
+
+ if (rv != NS_OK)
+ {
+ // try to fetch an nsIException possibly set by the method
+ nsresult rv2;
+ nsCOMPtr <nsIExceptionService> es;
+ es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv2);
+ if (NS_SUCCEEDED(rv2))
+ {
+ nsCOMPtr <nsIExceptionManager> em;
+ rv2 = es->GetCurrentExceptionManager (getter_AddRefs (em));
+ if (NS_SUCCEEDED(rv2))
+ {
+ rv2 = em->GetCurrentException (getter_AddRefs (exception));
+ if (NS_SUCCEEDED(rv2))
+ {
+ LOG(("got nsIException instance, will serialize\n"));
+ got_exception = PR_TRUE;
+ }
+ }
+ }
+ NS_ASSERTION(NS_SUCCEEDED(rv2), "failed to get/serialize exception");
+ if (NS_FAILED(rv2))
+ rv = rv2;
+ }
+
+end:
+ LOG(("sending INVOKE_REPLY: rv=%x\n", rv));
+
+ // balance CheckInstanceAndAddRef()
+ if (wrapper)
+ wrapper->Release();
+
+ ipcMessageWriter writer(64);
+
+ DConnectInvokeReply reply;
+ reply.opcode_major = DCON_OP_INVOKE_REPLY;
+ reply.opcode_minor = 0;
+ reply.flags = 0;
+ reply.request_index = invoke->request_index;
+ reply.result = rv;
+
+ if (got_exception)
+ reply.flags |= DCON_OP_FLAGS_REPLY_EXCEPTION;
+
+ writer.PutBytes(&reply, sizeof(reply));
+
+ nsVoidArray wrappers;
+
+ if (NS_SUCCEEDED(rv) && params)
+ {
+ // serialize out-params and retvals
+ for (i=0; i<paramCount; ++i)
+ {
+ const nsXPTParamInfo paramInfo = methodInfo->GetParam(i);
+
+ if (paramInfo.IsRetval() || paramInfo.IsOut())
+ {
+ const nsXPTType &type = paramInfo.GetType();
+
+ if (type.IsInterfacePointer())
+ {
+ nsID iid;
+ rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, type,
+ invoke->method_index, params, PR_TRUE, iid);
+ if (NS_SUCCEEDED(rv))
+ rv = SerializeInterfaceParam(writer, peer, iid,
+ (nsISupports *) params[i].val.p, wrappers);
+ }
+ else
+ rv = SerializeParam(writer, type, params[i]);
+
+ if (NS_FAILED(rv))
+ {
+ reply.result = rv;
+ break;
+ }
+ }
+ }
+
+ if (NS_SUCCEEDED(rv))
+ {
+ // serialize output array parameters after everything else since the
+ // deserialization procedure will need to get a size_is value which may be
+ // stored in any preceeding or following param
+ for (i=0; i<paramCount; ++i)
+ {
+ const nsXPTParamInfo &paramInfo = methodInfo->GetParam(i);
+
+ if (paramInfo.GetType().IsArray() &&
+ (paramInfo.IsRetval() || paramInfo.IsOut()))
+ {
+ rv = SerializeArrayParam(this, writer, peer, iinfo, invoke->method_index,
+ *methodInfo, params, PR_TRUE, paramInfo,
+ params[i].val.p, wrappers);
+ if (NS_FAILED(rv))
+ {
+ reply.result = rv;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (got_exception)
+ {
+ rv = SerializeException(writer, peer, exception, wrappers);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialize exception");
+ }
+
+ if (NS_FAILED(rv))
+ rv = IPC_SendMessage(peer, kDConnectTargetID, (const PRUint8 *) &reply, sizeof(reply));
+ else
+ rv = IPC_SendMessage(peer, kDConnectTargetID, writer.GetBuffer(), writer.GetSize());
+ if (NS_FAILED(rv))
+ {
+ LOG(("unable to send INVOKE_REPLY: rv=%x\n", rv));
+ ReleaseWrappers(wrappers, peer);
+ }
+
+ if (params)
+ {
+ // free individual elements of arrays (note: before freeing arrays
+ // themselves in FinishParam())
+ for (i=0; i<paramUsed; ++i)
+ {
+ const nsXPTParamInfo &paramInfo = methodInfo->GetParam(i);
+ if (paramInfo.GetType().IsArray())
+ FinishArrayParam(iinfo, invoke->method_index, *methodInfo,
+ params, PR_TRUE, paramInfo, params[i]);
+ }
+
+ for (i=0; i<paramUsed; ++i)
+ FinishParam(params[i]);
+ delete[] params;
+ }
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h
new file mode 100644
index 00000000..517b2650
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h
@@ -0,0 +1,365 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ * Dmitry A. Kuminov <dmik@innotek.de>
+ *
+ * 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 ***** */
+
+// DConnect service is multithreaded by default...
+#if !defined(DCONNECT_SINGLETHREADED) && !defined(DCONNECT_MULTITHREADED)
+#define DCONNECT_MULTITHREADED
+# ifdef VBOX
+//# define DCONNECT_WITH_IPRT_REQ_POOL
+# endif
+#endif
+
+#include "ipcIDConnectService.h"
+#include "ipcdclient.h"
+
+#include "nsIInterfaceInfo.h"
+#include "nsIInterfaceInfoManager.h"
+
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+#include "nsHashSets.h"
+#include "nsVoidArray.h"
+#include "nsAutoLock.h"
+#include "xptcall.h"
+#include "xptinfo.h"
+
+#if defined(DCONNECT_MULTITHREADED)
+# if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+
+# include <iprt/req.h>
+
+# else /* !DCONNECT_WITH_IPRT_REQ_POOL*/
+
+#include "ipcList.h"
+
+struct DConnectOp;
+
+struct DConnectRequest : public ipcListNode<DConnectRequest>
+{
+ DConnectRequest (PRUint32 aPeer, const DConnectOp *aOp, PRUint32 aOpLen)
+ : peer(aPeer)
+ , opLen(aOpLen)
+ {
+ op = (const DConnectOp *) malloc(aOpLen);
+ memcpy ((void *) op, aOp, aOpLen);
+ }
+ ~DConnectRequest() { free((void *) op); }
+
+ const PRUint32 peer;
+ const DConnectOp *op;
+ const PRUint32 opLen;
+};
+
+# endif // !DCONNECT_WITH_IPRT_REQ_POOL
+#endif // DCONNECT_MULTITHREADED
+
+class nsIException;
+class ipcMessageReader;
+class ipcMessageWriter;
+
+// a key class used to identify DConnectInstance objects stored in a hash table
+// by a composite of peer ID, XPCOM object pointer and IID this pointer represents
+
+class DConnectInstanceKey : public PLDHashEntryHdr
+{
+public:
+ struct Key
+ {
+ Key(PRUint32 aPeer, const nsISupports *aObj, const nsID *aIID)
+ : mPeer (aPeer), mObj (aObj), mIID (aIID) {}
+ const PRUint32 mPeer;
+ const nsISupports *mObj;
+ const nsIID *mIID;
+ };
+
+ typedef const Key &KeyType;
+ typedef const Key *KeyTypePointer;
+
+ DConnectInstanceKey(const Key *aKey) : mKey (*aKey) {}
+ DConnectInstanceKey(const DConnectInstanceKey &toCopy) : mKey (toCopy.mKey) {}
+ ~DConnectInstanceKey() {}
+
+ KeyType GetKey() const { return mKey; }
+ KeyTypePointer GetKeyPointer() const { return &mKey; }
+
+ PRBool KeyEquals(KeyTypePointer aKey) const {
+ return mKey.mPeer == aKey->mPeer &&
+ mKey.mObj == aKey->mObj &&
+ mKey.mIID->Equals(*aKey->mIID);
+ }
+
+ static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
+ static PLDHashNumber HashKey(KeyTypePointer aKey) {
+ return aKey->mPeer ^
+ (NS_PTR_TO_INT32(aKey->mObj) >> 2) ^
+ nsIDHashKey::HashKey(aKey->mIID);
+ }
+ enum { ALLOW_MEMMOVE = PR_TRUE };
+
+private:
+ const Key mKey;
+};
+
+class DConnectInstance;
+typedef nsDataHashtable<DConnectInstanceKey, DConnectInstance *> DConnectInstanceMap;
+
+// extend nsVoidHashSet for compatibility with some nsTHashtable methods
+class DConnectInstanceSet : public nsVoidHashSet
+{
+public:
+ PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE) {
+ return nsVoidHashSet::Init(initSize) == NS_OK;
+ }
+ void Clear() {
+ PL_DHashTableEnumerate(&mHashTable, PL_DHashStubEnumRemove, nsnull);
+ }
+};
+
+typedef PRUint64 DConAddr;
+
+// a key class used to identify DConnectStub objects stored in a hash table
+// by a composite of peer ID and DConAddr
+
+class DConnectStubKey : public PLDHashEntryHdr
+{
+public:
+ struct Key
+ {
+ Key(PRUint32 aPeer, const DConAddr aInstance)
+ : mPeer (aPeer), mInstance (aInstance) {}
+ const PRUint32 mPeer;
+ const DConAddr mInstance;
+ };
+
+ typedef const Key &KeyType;
+ typedef const Key *KeyTypePointer;
+
+ DConnectStubKey(const Key *aKey) : mKey (*aKey) {}
+ DConnectStubKey(const DConnectStubKey &toCopy) : mKey (toCopy.mKey) {}
+ ~DConnectStubKey() {}
+
+ KeyType GetKey() const { return mKey; }
+ KeyTypePointer GetKeyPointer() const { return &mKey; }
+
+ PRBool KeyEquals(KeyTypePointer aKey) const {
+ return mKey.mPeer == aKey->mPeer &&
+ mKey.mInstance == aKey->mInstance;
+ }
+
+ static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
+ static PLDHashNumber HashKey(KeyTypePointer aKey) {
+ return aKey->mPeer ^
+ (NS_PTR_TO_INT32(aKey->mInstance) >> 2);
+ }
+ enum { ALLOW_MEMMOVE = PR_TRUE };
+
+private:
+ const Key mKey;
+};
+
+// used elsewhere like nsAtomTable to safely represent the integral value
+// of an address.
+typedef PRUint64 PtrBits;
+
+// bit flag that defines if a PtrBits value represents a remote object
+#define PTRBITS_REMOTE_BIT 0x1
+
+class DConnectStub;
+typedef nsDataHashtable<DConnectStubKey, DConnectStub *> DConnectStubMap;
+
+class ipcDConnectService : public ipcIDConnectService
+ , public ipcIMessageObserver
+ , public ipcIClientObserver
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_IPCIDCONNECTSERVICE
+ NS_DECL_IPCIMESSAGEOBSERVER
+ NS_DECL_IPCICLIENTOBSERVER
+
+ ipcDConnectService();
+
+ NS_HIDDEN_(nsresult) Init();
+ NS_HIDDEN_(void) Shutdown();
+
+ NS_HIDDEN_(nsresult) GetInterfaceInfo(const nsID &iid, nsIInterfaceInfo **);
+ NS_HIDDEN_(nsresult) GetIIDForMethodParam(nsIInterfaceInfo *iinfo,
+ const nsXPTMethodInfo *methodInfo,
+ const nsXPTParamInfo &paramInfo,
+ const nsXPTType &type,
+ PRUint16 methodIndex,
+ nsXPTCMiniVariant *dispatchParams,
+ PRBool isXPTCVariantArray,
+ nsID &result);
+
+ NS_HIDDEN_(nsresult) SerializeInterfaceParam(ipcMessageWriter &writer,
+ PRUint32 peer, const nsID &iid,
+ nsISupports *obj,
+ nsVoidArray &wrappers);
+ NS_HIDDEN_(nsresult) DeserializeInterfaceParamBits(PtrBits bits, PRUint32 peer,
+ const nsID &iid,
+ nsISupports *&obj);
+
+ NS_HIDDEN_(nsresult) SerializeException(ipcMessageWriter &writer,
+ PRUint32 peer, nsIException *xcpt,
+ nsVoidArray &wrappers);
+ NS_HIDDEN_(nsresult) DeserializeException(ipcMessageReader &reader,
+ PRUint32 peer, nsIException **xcpt);
+
+ NS_HIDDEN_(void) ReleaseWrappers(nsVoidArray &wrappers, PRUint32 peer);
+
+ NS_HIDDEN_(nsresult) CreateStub(const nsID &, PRUint32, DConAddr, DConnectStub **);
+#if 0
+ NS_HIDDEN_(PRBool) FindStubAndAddRef(PRUint32, const DConAddr, DConnectStub **);
+#endif
+ // public only for DConnectStub::~DConnectStub()
+ NS_HIDDEN_(void) DeleteStub(DConnectStub *);
+
+ // public only for DConnectInstance::Release()
+ NS_HIDDEN_(void) DeleteInstance(DConnectInstance *, PRBool locked = PR_FALSE);
+ // public only for DConnectStub::CallMethod()
+ NS_HIDDEN_(PRBool) CheckInstanceAndAddRef(DConnectInstance *, PRUint32);
+
+ PRLock *StubLock() { return mStubLock; }
+ PRLock *StubQILock() { return mStubQILock; }
+
+ static nsRefPtr <ipcDConnectService> GetInstance() {
+ return nsRefPtr <ipcDConnectService> (mInstance);
+ }
+
+private:
+
+ NS_HIDDEN ~ipcDConnectService();
+
+ NS_HIDDEN_(nsresult) StoreInstance(DConnectInstance *);
+ NS_HIDDEN_(PRBool) FindInstanceAndAddRef(PRUint32,
+ const nsISupports *,
+ const nsIID *,
+ DConnectInstance **);
+
+ NS_HIDDEN_(nsresult) StoreStub(DConnectStub *);
+
+ NS_HIDDEN_(void) OnIncomingRequest(PRUint32 peer, const struct DConnectOp *op, PRUint32 opLen);
+
+ NS_HIDDEN_(void) OnSetup(PRUint32 peer, const struct DConnectSetup *, PRUint32 opLen);
+ NS_HIDDEN_(void) OnRelease(PRUint32 peer, const struct DConnectRelease *);
+ NS_HIDDEN_(void) OnInvoke(PRUint32 peer, const struct DConnectInvoke *, PRUint32 opLen);
+
+#if defined(DCONNECT_MULTITHREADED)
+# if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+ static DECLCALLBACK(void) ProcessMessageOnWorkerThread(ipcDConnectService *aThis, PRUint32 aSenderID, void *aData, PRUint32 aDataLen);
+# else
+ NS_HIDDEN_(nsresult) CreateWorker();
+# endif
+#endif
+
+private:
+ nsCOMPtr<nsIInterfaceInfoManager> mIIM;
+
+ // lock to protect access to instance sets and the disconnected flag
+ PRLock *mLock;
+
+ // table of local object instances allocated on behalf of a peer
+ // (keys are interface pointers of real objects these instances represent)
+ DConnectInstanceMap mInstances;
+ // hashset containing the same instances as above
+ // (used for quick parameter validity checks)
+ DConnectInstanceSet mInstanceSet;
+
+ // lock to protect access to mStubs and DConnectStub::mRefCntLevels
+ // (also guards every DConnectStub::Release call to provide atomicity)
+ PRLock *mStubLock;
+
+ // table of remote object stubs allocated to communicate with peer's instances
+ DConnectStubMap mStubs;
+
+ // this is true after IPC_Shutdown() has been called
+ PRBool mDisconnected;
+
+// member is never initialized or used, no point in wasting memory or making
+// someone believe it contains anything relevant
+#ifndef VBOX
+ // our IPC client ID
+ PRUint32 mSelfID;
+#endif
+
+ // global lock to protect access to protect DConnectStub::QueryInterface()
+ // (we cannot use mStubLock because it isn't supposed to be held long,
+ // like in case of an IPC call and such)
+ PRLock *mStubQILock;
+
+#if defined(DCONNECT_MULTITHREADED)
+# if defined(DCONNECT_WITH_IPRT_REQ_POOL)
+
+ /** Request pool. */
+ RTREQPOOL mhReqPool;
+
+# else
+
+ friend class DConnectWorker;
+
+ // pool of worker threads to serve incoming requests
+ nsVoidArray mWorkers;
+ // queue of pending requests
+ ipcList<DConnectRequest> mPendingQ;
+ // monitor to protect mPendingQ
+ PRMonitor *mPendingMon;
+ // number of waiting workers
+ PRUint32 mWaitingWorkers;
+ // monitor used to wait on changes in mWaitingWorkers.
+ PRMonitor *mWaitingWorkersMon;
+# endif
+#endif
+
+ // global ipcDConnectService instance for internal usage
+ static ipcDConnectService *mInstance;
+};
+
+#define IPC_DCONNECTSERVICE_CLASSNAME \
+ "ipcDConnectService"
+#define IPC_DCONNECTSERVICE_CONTRACTID \
+ "@mozilla.org/ipc/dconnect-service;1"
+#define IPC_DCONNECTSERVICE_CID \
+{ /* 63a5d9dc-4828-425a-bd50-bd10a4b26f2c */ \
+ 0x63a5d9dc, \
+ 0x4828, \
+ 0x425a, \
+ {0xbd, 0x50, 0xbd, 0x10, 0xa4, 0xb2, 0x6f, 0x2c} \
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/Makefile.in
new file mode 100644
index 00000000..2d511de2
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/Makefile.in
@@ -0,0 +1,33 @@
+# vim:set ts=8 sw=8 noet:
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = dconnect
+
+REQUIRES = ipcd \
+ nspr \
+ string \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = \
+ TestDConnect.cpp \
+ $(NULL)
+
+SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
+
+include $(topsrcdir)/config/config.mk
+
+LIBS = \
+ $(EXTRA_DSO_LIBS) \
+ $(XPCOM_LIBS) \
+ $(NSPR_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestClient.js b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestClient.js
new file mode 100644
index 00000000..8403fcdd
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestClient.js
@@ -0,0 +1,106 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * This file contains code that mirrors the code in TestDConnect.cpp:DoTest
+ */
+
+const ipcIService = Components.interfaces.ipcIService;
+const ipcIDConnectService = Components.interfaces.ipcIDConnectService;
+const nsIFile = Components.interfaces.nsIFile;
+const nsILocalFile = Components.interfaces.nsILocalFile;
+const nsIEventQueueService = Components.interfaces.nsIEventQueueService;
+
+// XXX use directory service for this
+const TEST_PATH = "/tmp";
+
+var serverID = 0;
+
+function findServer()
+{
+ var ipc = Components.classes["@mozilla.org/ipc/service;1"].getService(ipcIService);
+ serverID = ipc.resolveClientName("test-server");
+}
+
+function doTest()
+{
+ var dcon = Components.classes["@mozilla.org/ipc/dconnect-service;1"]
+ .getService(ipcIDConnectService);
+
+ var file = dcon.createInstanceByContractID(serverID, "@mozilla.org/file/local;1", nsIFile);
+
+ var localFile = file.QueryInterface(nsILocalFile);
+
+ localFile.initWithPath(TEST_PATH);
+
+ if (file.path != TEST_PATH)
+ {
+ dump("*** path test failed [path=" + file.path + "]\n");
+ return;
+ }
+
+ dump("file exists: " + file.exists() + "\n");
+
+ var clone = file.clone();
+
+ const node = "hello.txt";
+ clone.append(node);
+ dump("files are equal: " + file.equals(clone) + "\n");
+
+ if (!clone.exists())
+ clone.create(nsIFile.NORMAL_FILE_TYPE, 0600);
+
+ clone.moveTo(null, "helloworld.txt");
+
+ var localObj = Components.classes["@mozilla.org/file/local;1"].createInstance(nsILocalFile);
+ localObj.initWithPath(TEST_PATH);
+ dump("file.equals(localObj) = " + file.equals(localObj) + "\n");
+ dump("localObj.equals(file) = " + localObj.equals(file) + "\n");
+}
+
+function setupEventQ()
+{
+ var eqs = Components.classes["@mozilla.org/event-queue-service;1"]
+ .getService(nsIEventQueueService);
+ eqs.createMonitoredThreadEventQueue();
+}
+
+setupEventQ();
+findServer();
+dump("\n---------------------------------------------------\n");
+doTest();
+dump("---------------------------------------------------\n\n");
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestDConnect.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestDConnect.cpp
new file mode 100644
index 00000000..8eabe13c
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestDConnect.cpp
@@ -0,0 +1,268 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcIService.h"
+#include "ipcIDConnectService.h"
+#include "ipcCID.h"
+
+#include "nsIEventQueueService.h"
+#include "nsIServiceManager.h"
+#include "nsIComponentRegistrar.h"
+
+#include "nsXPCOMCID.h"
+#include "nsILocalFile.h"
+
+#include "nsString.h"
+#include "prmem.h"
+
+#if defined( XP_WIN ) || defined( XP_OS2 )
+#define TEST_PATH "c:"
+#else
+#define TEST_PATH "/tmp"
+#endif
+
+#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 ipcIService *gIpcServ = nsnull;
+
+static nsresult DoTest()
+{
+ nsresult rv;
+
+ nsCOMPtr<ipcIDConnectService> dcon = do_GetService("@mozilla.org/ipc/dconnect-service;1", &rv);
+ RETURN_IF_FAILED(rv, "getting dconnect service");
+
+ PRUint32 remoteClientID = 1;
+
+ nsCOMPtr<nsIFile> file;
+ rv = dcon->CreateInstanceByContractID(remoteClientID,
+ NS_LOCAL_FILE_CONTRACTID,
+ NS_GET_IID(nsIFile),
+ getter_AddRefs(file));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsISupports> sup = do_QueryInterface(file, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ printf("*** calling QueryInterface\n");
+ nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(file, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString path;
+ path.AssignLiteral(TEST_PATH);
+
+ printf("*** calling InitWithNativePath\n");
+ rv = localFile->InitWithPath(path);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString buf;
+ rv = file->GetPath(buf);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!buf.Equals(path))
+ {
+ NS_ConvertUTF16toUTF8 temp(buf);
+ printf("*** GetPath erroneously returned [%s]\n", temp.get());
+ return NS_ERROR_FAILURE;
+ }
+
+ PRBool exists;
+ rv = file->Exists(&exists);
+ if (NS_FAILED(rv))
+ {
+ printf("*** Exists test failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+ printf("File exists? [%d]\n", exists);
+
+ nsCOMPtr<nsIFile> clone;
+ rv = file->Clone(getter_AddRefs(clone));
+ if (NS_FAILED(rv))
+ {
+ printf("*** Clone test failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+
+ nsAutoString node;
+ node.AssignLiteral("hello.txt");
+
+ rv = clone->Append(node);
+ if (NS_FAILED(rv))
+ {
+ printf("*** Append test failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+
+ PRBool match;
+ rv = file->Equals(clone, &match);
+ if (NS_FAILED(rv))
+ {
+ printf("*** Equals test failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+ printf("Files are equals? [%d]\n", match);
+
+ // now test passing null for interface pointer
+
+ rv = clone->Exists(&exists);
+ if (NS_FAILED(rv))
+ {
+ printf("*** Exists test failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+ if (!exists)
+ {
+ rv = clone->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
+ if (NS_FAILED(rv))
+ {
+ printf("*** Create test failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ rv = clone->MoveTo(nsnull, NS_LITERAL_STRING("helloworld.txt"));
+ if (NS_FAILED(rv))
+ {
+ printf("*** MoveTo test failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+
+ // now test passing local objects to a remote object
+
+ nsCOMPtr<nsILocalFile> myLocalFile;
+ rv = NS_NewLocalFile(path, PR_TRUE, getter_AddRefs(myLocalFile));
+ if (NS_FAILED(rv))
+ {
+ printf("*** NS_NewLocalFile failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+
+ rv = file->Equals(myLocalFile, &match);
+ if (NS_FAILED(rv))
+ {
+ printf("*** second Equals test failed [rv=%x]\n", rv);
+ return NS_ERROR_FAILURE;
+ }
+ printf("Files are equals? [%d]\n", match);
+
+ printf("*** DoTest completed successfully :-)\n");
+ return NS_OK;
+}
+
+int main(int argc, char **argv)
+{
+ nsresult rv;
+
+ PRBool serverMode = PR_FALSE;
+ if (argc > 1)
+ {
+ if (strcmp(argv[1], "-server") == 0)
+ {
+ serverMode = PR_TRUE;
+ }
+ else
+ {
+ printf("usage: %s [-server]\n", argv[0]);
+ return -1;
+ }
+ }
+
+ {
+ nsCOMPtr<nsIServiceManager> servMan;
+ NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull);
+ nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
+ NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
+ if (registrar)
+ registrar->AutoRegister(nsnull);
+
+ // Create the Event Queue for this thread...
+ nsCOMPtr<nsIEventQueueService> 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<ipcIService> ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv));
+ RETURN_IF_FAILED(rv, "do_GetService(ipcServ)");
+ NS_ADDREF(gIpcServ = ipcServ);
+
+ if (!serverMode)
+ {
+ rv = DoTest();
+ RETURN_IF_FAILED(rv, "DoTest()");
+ }
+ else
+ {
+ gIpcServ->AddName("DConnectServer");
+ }
+
+ PLEvent *ev;
+ while (gKeepRunning)
+ {
+ gEventQ->WaitForEvent(&ev);
+ gEventQ->HandleEvent(ev);
+ }
+
+ NS_RELEASE(gIpcServ);
+
+ printf("*** processing remaining events\n");
+
+ // process any remaining events
+ 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");
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestServer.js b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestServer.js
new file mode 100644
index 00000000..a72e133b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestServer.js
@@ -0,0 +1,66 @@
+/* vim:set ts=2 sw=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * This file contains code for a "server" that does nothing more
+ * than set a name for itself on the IPC system so that the client
+ * can connect and control this process.
+ */
+
+const ipcIService = Components.interfaces.ipcIService;
+const nsIEventQueueService = Components.interfaces.nsIEventQueueService;
+const nsIEventQueue = Components.interfaces.nsIEventQueue;
+
+function registerServer()
+{
+ var ipc = Components.classes["@mozilla.org/ipc/service;1"].getService(ipcIService);
+ ipc.addName("test-server");
+}
+
+function runEventQ()
+{
+ var eqs = Components.classes["@mozilla.org/event-queue-service;1"]
+ .getService(nsIEventQueueService);
+ eqs.createMonitoredThreadEventQueue();
+ var queue = eqs.getSpecialEventQueue(eqs.CURRENT_THREAD_EVENT_QUEUE);
+
+ // this never returns
+ queue.eventLoop();
+}
+
+registerServer();
+runEventQ();
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in
new file mode 100644
index 00000000..4b94a31f
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in
@@ -0,0 +1,52 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = public src
+
+ifdef ENABLE_TESTS
+DIRS += test
+endif
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/Makefile.in
new file mode 100644
index 00000000..9a08abdb
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/Makefile.in
@@ -0,0 +1,58 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+XPIDL_MODULE = ipcd_lock
+
+EXPORTS = \
+ ipcLockCID.h \
+ $(NULL)
+
+XPIDLSRCS = \
+ ipcILockService.idl \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcILockService.idl b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcILockService.idl
new file mode 100644
index 00000000..1cbf8651
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcILockService.idl
@@ -0,0 +1,65 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * This service provides named interprocess locking.
+ */
+[scriptable, uuid(9f6dbe15-d851-4b00-912a-5ac0be88a409)]
+interface ipcILockService : nsISupports
+{
+ /**
+ * Call this method to acquire a named interprocess lock.
+ *
+ * @param aLockName
+ * specifies the name of the lock
+ * @param aWaitIfBusy
+ * wait for the lock to become available; otherwise, fail if lock
+ * is already held by some other process.
+ */
+ void acquireLock(in string aLockName,
+ in boolean aWaitIfBusy);
+
+ /**
+ * Call this method to release a named lock.
+ *
+ * @param aLockName
+ * specifies the name of the lock
+ */
+ void releaseLock(in string aLockName);
+};
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcLockCID.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcLockCID.h
new file mode 100644
index 00000000..ba756d9b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcLockCID.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 <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcLockCID_h__
+#define ipcLockCID_h__
+
+#define IPC_LOCKSERVICE_CLASSNAME \
+ "ipcLockService"
+#define IPC_LOCKSERVICE_CONTRACTID \
+ "@mozilla.org/ipc/lock-service;1"
+#define IPC_LOCKSERVICE_CID \
+{ /* d9e56bf8-e32e-4b6d-87f1-06d73b0ce7ca */ \
+ 0xd9e56bf8, \
+ 0xe32e, \
+ 0x4b6d, \
+ {0x87, 0xf1, 0x06, 0xd7, 0x3b, 0x0c, 0xe7, 0xca} \
+}
+
+#endif // !ipcLockCID_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/Makefile.in
new file mode 100644
index 00000000..26d943a8
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/Makefile.in
@@ -0,0 +1,69 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = module
+
+MODULE = ipcd
+LIBRARY_NAME = ipcdlock_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME = ipcd
+
+FORCE_USE_PIC = 1
+
+REQUIRES = \
+ xpcom \
+ string \
+ $(NULL)
+
+CPPSRCS = \
+ ipcLockProtocol.cpp \
+ ipcLockService.cpp \
+ $(NULL)
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/../../../shared/src \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp
new file mode 100644
index 00000000..5a7e7755
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp
@@ -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 <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include <string.h>
+#include "prlog.h"
+#include "ipcLockProtocol.h"
+
+//-----------------------------------------------------------------------------
+
+static inline PRUint8 get_opcode(const PRUint8 *buf)
+{
+ return (buf[0] & 0x0f);
+}
+
+static inline PRUint8 get_flags(const PRUint8 *buf)
+{
+ return (buf[0] & 0xf0) >> 4;
+}
+
+static inline const char *get_key(const PRUint8 *buf)
+{
+ return ((const char *) buf) + 1;
+}
+
+//-----------------------------------------------------------------------------
+
+PRUint8 *
+IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen)
+{
+ PRUint32 len = 1 // header byte
+ + strlen(msg->key) // key
+ + 1; // null terminator
+
+ PRUint8 *buf = (PRUint8 *) ::operator new(len);
+ if (!buf)
+ return NULL;
+
+ buf[0] = (msg->opcode | (msg->flags << 4));
+
+ memcpy(&buf[1], msg->key, len - 1);
+ *bufLen = len;
+ return buf;
+}
+
+void
+IPC_UnflattenLockMsg(const PRUint8 *buf, PRUint32 bufLen, ipcLockMsg *msg)
+{
+ PR_ASSERT(bufLen > 2); // malformed buffer otherwise
+ msg->opcode = get_opcode(buf);
+ msg->flags = get_flags(buf);
+ msg->key = get_key(buf);
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h
new file mode 100644
index 00000000..b74b5cde
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h
@@ -0,0 +1,98 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcLockProtocol_h__
+#define ipcLockProtocol_h__
+
+#include "prtypes.h"
+
+//
+// ipc lock message format:
+//
+// +----------------------------------+
+// | opcode : 4 bits |
+// +----------------------------------+
+// | flags : 4 bits |
+// +----------------------------------+
+// | key : null terminated string |
+// +----------------------------------+
+//
+
+// lock opcodes
+#define IPC_LOCK_OP_ACQUIRE 1
+#define IPC_LOCK_OP_RELEASE 2
+#define IPC_LOCK_OP_STATUS_ACQUIRED 3
+#define IPC_LOCK_OP_STATUS_FAILED 4
+#define IPC_LOCK_OP_STATUS_BUSY 5
+
+// lock flags
+#define IPC_LOCK_FL_NONBLOCKING 1
+
+// data structure for representing lock request message
+struct ipcLockMsg
+{
+ PRUint8 opcode;
+ PRUint8 flags;
+ const char * key;
+};
+
+//
+// flatten a lock message
+//
+// returns a malloc'd buffer containing the flattened message. on return,
+// bufLen contains the length of the flattened message.
+//
+PRUint8 *IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen);
+
+//
+// unflatten a lock message. upon return, msg->key points into buf, so
+// buf must not be deallocated until after msg is no longer needed.
+//
+void IPC_UnflattenLockMsg(const PRUint8 *buf, PRUint32 bufLen, ipcLockMsg *msg);
+
+//
+// TargetID for message passing
+//
+#define IPC_LOCK_TARGETID \
+{ /* 703ada8a-2d38-4d5d-9d39-03d1ccceb567 */ \
+ 0x703ada8a, \
+ 0x2d38, \
+ 0x4d5d, \
+ {0x9d, 0x39, 0x03, 0xd1, 0xcc, 0xce, 0xb5, 0x67} \
+}
+
+#endif // !ipcLockProtocol_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.cpp
new file mode 100644
index 00000000..771aa787
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.cpp
@@ -0,0 +1,168 @@
+/* vim:set ts=4 sw=4 sts=4 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include "nsDependentString.h"
+#include "nsHashKeys.h"
+#include "nsAutoPtr.h"
+#include "ipcLockService.h"
+#include "ipcLockProtocol.h"
+#include "ipcLog.h"
+#include "prthread.h"
+
+static const nsID kLockTargetID = IPC_LOCK_TARGETID;
+
+//-----------------------------------------------------------------------------
+
+struct ipcPendingLock
+{
+ const char *name;
+ nsresult status;
+ PRBool complete;
+};
+
+//-----------------------------------------------------------------------------
+
+nsresult
+ipcLockService::Init()
+{
+ if (PR_NewThreadPrivateIndex(&mTPIndex, nsnull) != PR_SUCCESS)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // Configure OnMessageAvailable to be called on the IPC thread. This is
+ // done to allow us to proxy OnAcquireLockComplete events to the right
+ // thread immediately even if the main thread is blocked waiting to acquire
+ // some other lock synchronously.
+
+ return IPC_DefineTarget(kLockTargetID, this, PR_FALSE);
+}
+
+NS_IMPL_THREADSAFE_ISUPPORTS2(ipcLockService, ipcILockService, ipcIMessageObserver)
+
+NS_IMETHODIMP
+ipcLockService::AcquireLock(const char *lockName, PRBool waitIfBusy)
+{
+ LOG(("ipcLockService::AcquireLock [lock=%s wait=%u]\n", lockName, waitIfBusy));
+
+ ipcLockMsg msg;
+ msg.opcode = IPC_LOCK_OP_ACQUIRE;
+ msg.flags = (waitIfBusy ? 0 : IPC_LOCK_FL_NONBLOCKING);
+ msg.key = lockName;
+
+ PRUint32 bufLen;
+ nsAutoPtr<PRUint8> buf( IPC_FlattenLockMsg(&msg, &bufLen) );
+ if (!buf)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ ipcPendingLock pendingLock;
+ pendingLock.name = lockName;
+ pendingLock.status = 0xDEADBEEF; // something bogus
+ pendingLock.complete = PR_FALSE;
+ if (PR_SetThreadPrivate(mTPIndex, &pendingLock) != PR_SUCCESS)
+ return NS_ERROR_UNEXPECTED;
+
+ // prevent our OnMessageAvailable from being called until we explicitly ask
+ // for it to be called via IPC_WaitMessage.
+ IPC_DISABLE_MESSAGE_OBSERVER_FOR_SCOPE(kLockTargetID);
+
+ nsresult rv = IPC_SendMessage(0, kLockTargetID, buf, bufLen);
+ if (NS_SUCCEEDED(rv)) {
+ do {
+ // block the calling thread until we get a response from the daemon
+ rv = IPC_WaitMessage(0, kLockTargetID, this, nsnull, PR_INTERVAL_NO_TIMEOUT);
+ }
+ while (NS_SUCCEEDED(rv) && !pendingLock.complete);
+
+ if (NS_SUCCEEDED(rv))
+ rv = pendingLock.status;
+ }
+
+ // we could clear the TPD, but that isn't really necessary.
+
+ return rv;
+}
+
+NS_IMETHODIMP
+ipcLockService::ReleaseLock(const char *lockName)
+{
+ LOG(("ipcLockService::ReleaseLock [lock=%s]\n", lockName));
+
+ ipcLockMsg msg;
+ msg.opcode = IPC_LOCK_OP_RELEASE;
+ msg.flags = 0;
+ msg.key = lockName;
+
+ PRUint32 bufLen;
+ PRUint8 *buf = IPC_FlattenLockMsg(&msg, &bufLen);
+ if (!buf)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ nsresult rv = IPC_SendMessage(0, kLockTargetID, buf, bufLen);
+ delete buf;
+
+ if (NS_FAILED(rv))
+ return rv;
+
+ return NS_OK;
+}
+
+// called on the same thread that called IPC_WaitMessage
+NS_IMETHODIMP
+ipcLockService::OnMessageAvailable(PRUint32 unused, const nsID &target,
+ const PRUint8 *data, PRUint32 dataLen)
+{
+ ipcLockMsg msg;
+ IPC_UnflattenLockMsg(data, dataLen, &msg);
+
+ LOG(("ipcLockService::OnMessageAvailable [lock=%s opcode=%u]\n", msg.key, msg.opcode));
+
+ ipcPendingLock *pendingLock = (ipcPendingLock *) PR_GetThreadPrivate(mTPIndex);
+ if (strcmp(pendingLock->name, msg.key) == 0) {
+ pendingLock->complete = PR_TRUE;
+ if (msg.opcode == IPC_LOCK_OP_STATUS_ACQUIRED)
+ pendingLock->status = NS_OK;
+ else
+ pendingLock->status = NS_ERROR_FAILURE;
+ return NS_OK;
+ }
+
+ LOG(("message does not match; waiting for another...\n"));
+
+ // else, we got a message that another thread is waiting to receive.
+ return IPC_WAIT_NEXT_MESSAGE;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.h
new file mode 100644
index 00000000..6014172b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.h
@@ -0,0 +1,63 @@
+/* vim:set ts=4 sw=4 sts=4 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcLockService_h__
+#define ipcLockService_h__
+
+#include "ipcILockService.h"
+#include "ipcdclient.h"
+
+//-----------------------------------------------------------------------------
+
+class ipcLockService : public ipcILockService
+ , public ipcIMessageObserver
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_IPCILOCKSERVICE
+ NS_DECL_IPCIMESSAGEOBSERVER
+
+ NS_HIDDEN_(nsresult) Init();
+
+private:
+ PRUintn mTPIndex;
+};
+
+//-----------------------------------------------------------------------------
+
+#endif // !ipcLockService_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/Makefile.in
new file mode 100644
index 00000000..b35db1bc
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/Makefile.in
@@ -0,0 +1,92 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+LIBRARY_NAME = lockmodule
+ifeq ($(OS_ARCH), OS2)
+SHORT_LIBNAME = lockmod
+endif
+MODULE_NAME = ipcd
+
+FORCE_SHARED_LIB = 1
+NO_DIST_INSTALL = 1
+NO_INSTALL = 1
+
+ifeq ($(OS_ARCH),Darwin)
+NO_COMPONENT_LINK_MAP = 1
+MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS =
+endif
+
+# required for #include "nsID.h"
+REQUIRES = \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = ipcLockModule.cpp
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/.. \
+ $(NULL)
+
+EXTRA_OBJS = ../ipcLockProtocol.$(OBJ_SUFFIX)
+
+EXTRA_DSO_LDOPTS = \
+ $(LIBS_DIR) \
+ $(NSPR_LIBS) \
+ $(EXTRA_DSO_LIBS) \
+ $(EXTRA_OBJS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+_IPC_FILES = \
+ $(DLL_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/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp
new file mode 100644
index 00000000..151c0f89
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp
@@ -0,0 +1,337 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "ipcModuleUtil.h"
+#include "ipcLockProtocol.h"
+#include "plhash.h"
+#include "plstr.h"
+
+#ifdef DEBUG
+#define LOG(args) printf args
+#else
+#define LOG(args)
+#endif
+
+static const nsID kLockTargetID = IPC_LOCK_TARGETID;
+
+static void
+ipcLockModule_Send(PRUint32 cid, const char *key, PRUint8 opcode)
+{
+ ipcLockMsg msg = { opcode, 0, key };
+ PRUint32 bufLen;
+ PRUint8 *buf = IPC_FlattenLockMsg(&msg, &bufLen);
+ if (!buf)
+ return;
+ IPC_SendMsg(cid, kLockTargetID, buf, bufLen);
+ free(buf);
+}
+
+//-----------------------------------------------------------------------------
+
+//
+// gLockTable stores mapping from lock name to ipcLockContext
+//
+static PLHashTable *gLockTable = NULL;
+
+//-----------------------------------------------------------------------------
+
+struct ipcLockContext
+{
+ PRUint32 mOwnerID; // client ID of this lock's owner
+ struct ipcLockContext *mNextPending; // pointer to client next in line to
+ // acquire this lock.
+
+ ipcLockContext(PRUint32 ownerID)
+ : mOwnerID(ownerID)
+ , mNextPending(NULL) {}
+};
+
+//-----------------------------------------------------------------------------
+
+PR_STATIC_CALLBACK(void *)
+ipcLockModule_AllocTable(void *pool, PRSize size)
+{
+ return malloc(size);
+}
+
+PR_STATIC_CALLBACK(void)
+ipcLockModule_FreeTable(void *pool, void *item)
+{
+ free(item);
+}
+
+PR_STATIC_CALLBACK(PLHashEntry *)
+ipcLockModule_AllocEntry(void *pool, const void *key)
+{
+ return (PLHashEntry *) malloc(sizeof(PLHashEntry));
+}
+
+PR_STATIC_CALLBACK(void)
+ipcLockModule_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+ PL_strfree((char *) he->key);
+ free(he);
+}
+
+static const PLHashAllocOps ipcLockModule_AllocOps = {
+ ipcLockModule_AllocTable,
+ ipcLockModule_FreeTable,
+ ipcLockModule_AllocEntry,
+ ipcLockModule_FreeEntry
+};
+
+//-----------------------------------------------------------------------------
+
+static void
+ipcLockModule_AcquireLock(PRUint32 cid, PRUint8 flags, const char *key)
+{
+ LOG(("$$$ acquiring lock [key=%s]\n", key));
+
+ if (!gLockTable)
+ return;
+
+ ipcLockContext *ctx;
+
+ ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key);
+ if (ctx) {
+ //
+ // lock is already acquired, add this client to the queue. make
+ // sure this client doesn't already own the lock or live on the queue.
+ //
+ while (ctx->mOwnerID != cid && ctx->mNextPending)
+ ctx = ctx->mNextPending;
+ if (ctx->mOwnerID != cid) {
+ //
+ // if nonblocking, then send busy status message. otherwise,
+ // proceed to add this client to the pending queue.
+ //
+ if (flags & IPC_LOCK_FL_NONBLOCKING)
+ ipcLockModule_Send(cid, key, IPC_LOCK_OP_STATUS_BUSY);
+ else
+ ctx->mNextPending = new ipcLockContext(cid);
+ }
+ }
+ else {
+ //
+ // ok, add this lock to the table, and notify client that it now owns
+ // the lock!
+ //
+ ctx = new ipcLockContext(cid);
+ if (!ctx)
+ return;
+
+ PL_HashTableAdd(gLockTable, PL_strdup(key), ctx);
+
+ ipcLockModule_Send(cid, key, IPC_LOCK_OP_STATUS_ACQUIRED);
+ }
+}
+
+static PRBool
+ipcLockModule_ReleaseLockHelper(PRUint32 cid, const char *key, ipcLockContext *ctx)
+{
+ LOG(("$$$ releasing lock [key=%s]\n", key));
+
+ PRBool removeEntry = PR_FALSE;
+
+ //
+ // lock is already acquired _or_ maybe client is on the pending list.
+ //
+ if (ctx->mOwnerID == cid) {
+ if (ctx->mNextPending) {
+ //
+ // remove this element from the list. since this is the
+ // first element in the list, instead of removing it we
+ // shift the data from the next context into this one and
+ // delete the next context.
+ //
+ ipcLockContext *next = ctx->mNextPending;
+ ctx->mOwnerID = next->mOwnerID;
+ ctx->mNextPending = next->mNextPending;
+ delete next;
+ //
+ // notify client that it now owns the lock
+ //
+ ipcLockModule_Send(ctx->mOwnerID, key, IPC_LOCK_OP_STATUS_ACQUIRED);
+ }
+ else {
+ delete ctx;
+ removeEntry = PR_TRUE;
+ }
+ }
+ else {
+ ipcLockContext *prev;
+ for (;;) {
+ prev = ctx;
+ ctx = ctx->mNextPending;
+ if (!ctx)
+ break;
+ if (ctx->mOwnerID == cid) {
+ // remove ctx from list
+ prev->mNextPending = ctx->mNextPending;
+ delete ctx;
+ break;
+ }
+ }
+ }
+
+ return removeEntry;
+}
+
+static void
+ipcLockModule_ReleaseLock(PRUint32 cid, const char *key)
+{
+ if (!gLockTable)
+ return;
+
+ ipcLockContext *ctx;
+
+ ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key);
+ if (ctx && ipcLockModule_ReleaseLockHelper(cid, key, ctx))
+ PL_HashTableRemove(gLockTable, key);
+}
+
+PR_STATIC_CALLBACK(PRIntn)
+ipcLockModule_ReleaseByCID(PLHashEntry *he, PRIntn i, void *arg)
+{
+ PRUint32 cid = *(PRUint32 *) arg;
+
+ ipcLockContext *ctx = (ipcLockContext *) he->value;
+ if (ctx->mOwnerID != cid)
+ return HT_ENUMERATE_NEXT;
+
+ LOG(("$$$ ipcLockModule_ReleaseByCID [cid=%u key=%s he=%p]\n",
+ cid, (char*)he->key, (void*)he));
+
+ if (ipcLockModule_ReleaseLockHelper(cid, (const char *) he->key, ctx))
+ return HT_ENUMERATE_REMOVE;
+
+ return HT_ENUMERATE_NEXT;
+}
+
+//-----------------------------------------------------------------------------
+
+static void
+ipcLockModule_Init()
+{
+ LOG(("$$$ ipcLockModule_Init\n"));
+
+ gLockTable = PL_NewHashTable(32,
+ PL_HashString,
+ PL_CompareStrings,
+ PL_CompareValues,
+ &ipcLockModule_AllocOps,
+ NULL);
+}
+
+static void
+ipcLockModule_Shutdown()
+{
+ LOG(("$$$ ipcLockModule_Shutdown\n"));
+
+ if (gLockTable) {
+ // XXX walk table destroying all ipcLockContext objects
+
+ PL_HashTableDestroy(gLockTable);
+ gLockTable = NULL;
+ }
+}
+
+static void
+ipcLockModule_HandleMsg(ipcClientHandle client,
+ const nsID &target,
+ const void *data,
+ PRUint32 dataLen)
+{
+ PRUint32 cid = IPC_GetClientID(client);
+
+ LOG(("$$$ ipcLockModule_HandleMsg [cid=%u]\n", cid));
+
+ ipcLockMsg msg;
+ IPC_UnflattenLockMsg((const PRUint8 *) data, dataLen, &msg);
+
+ switch (msg.opcode) {
+ case IPC_LOCK_OP_ACQUIRE:
+ ipcLockModule_AcquireLock(cid, msg.flags, msg.key);
+ break;
+ case IPC_LOCK_OP_RELEASE:
+ ipcLockModule_ReleaseLock(cid, msg.key);
+ break;
+ default:
+ PR_NOT_REACHED("invalid opcode");
+ }
+}
+
+static void
+ipcLockModule_ClientUp(ipcClientHandle client)
+{
+ LOG(("$$$ ipcLockModule_ClientUp [%u]\n", IPC_GetClientID(client)));
+}
+
+static void
+ipcLockModule_ClientDown(ipcClientHandle client)
+{
+ PRUint32 cid = IPC_GetClientID(client);
+
+ LOG(("$$$ ipcLockModule_ClientDown [%u]\n", cid));
+
+ //
+ // enumerate lock table, release any locks held by this client.
+ //
+
+ PL_HashTableEnumerateEntries(gLockTable, ipcLockModule_ReleaseByCID, &cid);
+}
+
+//-----------------------------------------------------------------------------
+
+static ipcModuleMethods gLockMethods =
+{
+ IPC_MODULE_METHODS_VERSION,
+ ipcLockModule_Init,
+ ipcLockModule_Shutdown,
+ ipcLockModule_HandleMsg,
+ ipcLockModule_ClientUp,
+ ipcLockModule_ClientDown
+};
+
+static ipcModuleEntry gLockModuleEntry[] =
+{
+ { IPC_LOCK_TARGETID, &gLockMethods }
+};
+
+IPC_IMPL_GETMODULES(ipcLockModule, gLockModuleEntry)
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/Makefile.in
new file mode 100644
index 00000000..bcf9299a
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/Makefile.in
@@ -0,0 +1,67 @@
+# vim:set ts=8 sw=8 noet:
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is IBM Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2004
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@meer.net>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = dconnect
+
+REQUIRES = ipcd \
+ nspr \
+ string \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = \
+ TestIPCLocks.cpp \
+ $(NULL)
+
+SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
+
+include $(topsrcdir)/config/config.mk
+
+LIBS = \
+ $(EXTRA_DSO_LIBS) \
+ $(XPCOM_LIBS) \
+ $(NSPR_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp
new file mode 100644
index 00000000..f35e8434
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp
@@ -0,0 +1,244 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This test program spawns N copies of itself, and each copy spawns M threads.
+// Each thread acquires and releases a named, interprocess lock.
+// Randomized delays are injected at various points to exercise the system, and
+// help expose any race conditions that may exist.
+//
+// Usage: TestIPCLocks [-N]
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "ipcILockService.h"
+#include "ipcLockCID.h"
+#include "nsIServiceManagerUtils.h"
+#include "nsIEventQueueService.h"
+#include "nsCOMPtr.h"
+#include "nsXPCOM.h"
+#include "prproces.h"
+#include "prprf.h"
+
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+#include <unistd.h>
+static unsigned GetPID()
+{
+ return (unsigned) getpid();
+}
+#elif defined(XP_WIN)
+#include <windows.h>
+static unsigned GetPID()
+{
+ return (unsigned) GetCurrentProcessId();
+}
+#else
+static unsigned int GetPID()
+{
+ return 0; // implement me!
+}
+#endif
+
+static void LOG(const char *fmt, ... )
+{
+ va_list ap;
+ va_start(ap, fmt);
+ PRUint32 nb = 0;
+ char buf[512];
+
+ nb = PR_snprintf(buf, sizeof(buf), "[%u:%p] ", GetPID(), PR_GetCurrentThread());
+
+ PR_vsnprintf(buf + nb, sizeof(buf) - nb, fmt, ap);
+ buf[sizeof(buf) - 1] = '\0';
+
+ fwrite(buf, strlen(buf), 1, stdout);
+ fflush(stdout);
+
+ va_end(ap);
+}
+
+static void RandomSleep(PRUint32 fromMS, PRUint32 toMS)
+{
+ PRUint32 ms = fromMS + (PRUint32) ((toMS - fromMS) * ((double) rand() / RAND_MAX));
+ //LOG("putting thread to sleep for %u ms\n", ms);
+ PR_Sleep(PR_MillisecondsToInterval(ms));
+}
+
+static ipcILockService *gLockService;
+
+PR_STATIC_CALLBACK(void) TestThread(void *arg)
+{
+ const char *lockName = (const char *) arg;
+
+ LOG("entering TestThread [lock=%s]\n", lockName);
+
+ nsresult rv;
+
+ RandomSleep(1000, 1100);
+
+ //LOG("done sleeping\n");
+
+ rv = gLockService->AcquireLock(lockName, PR_TRUE);
+ if (NS_SUCCEEDED(rv))
+ {
+ //LOG("acquired lock \"%s\"\n", lockName);
+ RandomSleep(500, 1000);
+ //LOG("releasing lock \"%s\"\n", lockName);
+ rv = gLockService->ReleaseLock(lockName);
+ if (NS_FAILED(rv))
+ {
+ LOG("failed to release lock [rv=%x]\n", rv);
+ NS_ERROR("failed to release lock");
+ }
+ }
+ else
+ {
+ LOG("failed to acquire lock [rv=%x]\n", rv);
+ NS_NOTREACHED("failed to acquire lock");
+ }
+
+ LOG("exiting TestThread [lock=%s rv=%x]\n", lockName, rv);
+}
+
+static const char *kLockNames[] = {
+ "foopy",
+ "test",
+ "1",
+ "xyz",
+ "moz4ever",
+ nsnull
+};
+
+static nsresult DoTest()
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIEventQueueService> eqs =
+ do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv))
+ return rv;
+
+ rv = eqs->CreateMonitoredThreadEventQueue();
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsIEventQueue> eq;
+ rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eq));
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<ipcILockService> lockService =
+ do_GetService(IPC_LOCKSERVICE_CONTRACTID);
+
+ gLockService = lockService;
+
+ PRThread *threads[10] = {0};
+ int i = 0;
+
+ for (const char **lockName = kLockNames; *lockName; ++lockName, ++i)
+ {
+ threads[i] = PR_CreateThread(PR_USER_THREAD,
+ TestThread,
+ (void *) *lockName,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ 0);
+ }
+
+ for (i=0; threads[i]; ++i)
+ {
+ PR_JoinThread(threads[i]);
+ threads[i] = nsnull;
+ }
+
+ gLockService = nsnull;
+
+ LOG("joined with all threads; exiting DoTest\n");
+ return NS_OK;
+}
+
+int main(int argc, char **argv)
+{
+ LOG("entering main\n");
+
+ int numProcs = 10;
+
+ // if this is a child process, then just run the test
+ if (argc > 1)
+ {
+ if (strcmp(argv[1], "-child") == 0)
+ {
+ RandomSleep(1000, 1000);
+ LOG("running child test\n");
+ NS_InitXPCOM2(nsnull, nsnull, nsnull);
+ DoTest();
+ NS_ShutdownXPCOM(nsnull);
+ return 0;
+ }
+ else if (argv[1][0] == '-')
+ {
+ // argument is a number
+ numProcs = atoi(argv[1] + 1);
+ if (numProcs == 0)
+ {
+ printf("### usage: TestIPCLocks [-N]\n"
+ "where, N is the number of test processes to spawn.\n");
+ return -1;
+ }
+ }
+ }
+
+ LOG("sleeping for 1 second\n");
+ PR_Sleep(PR_SecondsToInterval(1));
+
+ PRProcess **procs = (PRProcess **) malloc(sizeof(PRProcess*) * numProcs);
+ int i;
+
+ // else, spawn the child processes
+ for (i=0; i<numProcs; ++i)
+ {
+ char *const argv[] = {"./TestIPCLocks", "-child", nsnull};
+ LOG("spawning child test\n");
+ procs[i] = PR_CreateProcess("./TestIPCLocks", argv, nsnull, nsnull);
+ }
+
+ PRInt32 exitCode;
+ for (i=0; i<numProcs; ++i)
+ PR_WaitProcess(procs[i], &exitCode);
+
+ return 0;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/Makefile.in
new file mode 100644
index 00000000..5f80740d
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/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 Transaction Manager.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corp.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# John Gaunt <jgaunt@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = common module public src
+
+ifdef ENABLE_TESTS
+DIRS += test
+endif
+
+include $(topsrcdir)/config/rules.mk
+
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/.cvsignore
new file mode 100644
index 00000000..b292dd21
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/.cvsignore
@@ -0,0 +1,9 @@
+Makefile
+module.rc
+module.res
+tmModule.obj
+transmngr_client.dll
+transmngr_client.pdb
+transmngr_client.exp
+transmngr_client.lib
+transmngr_client.ilk \ No newline at end of file
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/Makefile.in
new file mode 100644
index 00000000..87277839
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/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 Transaction Manager.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corp.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# John Gaunt <jgaunt@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = transmngr
+LIBRARY_NAME = transmngr_client
+EXPORT_LIBRARY = 1
+IS_COMPONENT = 1
+MODULE_NAME = transmngr
+
+REQUIRES = ipcd \
+ string \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = tmModule.cpp
+EXPORTS = tmCID.h
+
+SHARED_LIBRARY_LIBS = \
+ $(DIST)/lib/$(LIB_PREFIX)transmngr_s.$(LIB_SUFFIX) \
+ $(DIST)/lib/$(LIB_PREFIX)transmngrcom_s.$(LIB_SUFFIX) \
+ $(NULL)
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/../src \
+ -I$(srcdir)/../common \
+ $(NULL)
+
+EXTRA_DSO_LDOPTS = \
+ $(LIBS_DIR) \
+ $(EXTRA_DSO_LIBS) \
+ $(MOZ_COMPONENT_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmCID.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmCID.h
new file mode 100644
index 00000000..8ca23b84
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmCID.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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef tmCID_h__
+#define tmCID_h__
+
+#define TRANSACTION_SERVICE_CLASSNAME \
+ "tmTransactionService"
+#define TRANSACTION_SERVICE_CONTRACTID \
+ "@mozilla.org/transaction/service;1"
+#define TRANSACTION_SERVICE_CID \
+{ /* 1403adf4-94d1-4c67-a8ae-d9f86972d378 */ \
+ 0x1403adf4, \
+ 0x94d1, \
+ 0x4c67, \
+ {0xa8, 0xae, 0xd9, 0xf8, 0x69, 0x72, 0xd3, 0x78} \
+}
+
+#endif // !tmCID_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmModule.cpp
new file mode 100644
index 00000000..2853ba0a
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmModule.cpp
@@ -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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsICategoryManager.h"
+#include "nsIGenericFactory.h"
+#include "nsIServiceManager.h"
+#include "tmCID.h"
+#include "tmTransactionService.h"
+
+//-----------------------------------------------------------------------------
+// Define the contructor function for the objects
+//
+// NOTE: This creates an instance of objects by using the default constructor
+//-----------------------------------------------------------------------------
+NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService)
+
+//-----------------------------------------------------------------------------
+// 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[] = {
+ { TRANSACTION_SERVICE_CLASSNAME,
+ TRANSACTION_SERVICE_CID,
+ TRANSACTION_SERVICE_CONTRACTID,
+ tmTransactionServiceConstructor },
+ /*
+ tmTransactionServiceRegisterProc,
+ tmTransactionServiceUnregisterProc },
+ */
+};
+
+//-----------------------------------------------------------------------------
+// Implement the NSGetModule() exported function for your module
+// and the entire implementation of the module object.
+//-----------------------------------------------------------------------------
+NS_IMPL_NSGETMODULE(transmngr, components)
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/.cvsignore
new file mode 100644
index 00000000..df8a43a2
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/.cvsignore
@@ -0,0 +1,5 @@
+Makefile
+tmTransaction.obj
+tmVector.obj
+transmgrcom_s.pdb
+transmgrcom_s.lib
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/Makefile.in
new file mode 100644
index 00000000..4521c39a
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/Makefile.in
@@ -0,0 +1,61 @@
+# ***** 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 Transaction Manager.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corp.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# John Gaunt <jgaunt@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+LIBRARY_NAME = transmgrcom_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME = ipcd
+
+FORCE_USE_PIC = 1
+
+REQUIRES = \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = \
+ tmTransaction.cpp \
+ tmVector.cpp \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp
new file mode 100644
index 00000000..5fb7e5bf
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp
@@ -0,0 +1,107 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include "tmTransaction.h"
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+# include <iprt/mem.h>
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructor(s) & Destructor
+
+tmTransaction::~tmTransaction() {
+ if (mHeader)
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ RTMemFree(mHeader);
+#else
+ free(mHeader);
+#endif
+}
+
+// call only once per lifetime of object. does not reclaim the
+// raw message, only sets it.
+nsresult
+tmTransaction::Init(PRUint32 aOwnerID,
+ PRInt32 aQueueID,
+ PRUint32 aAction,
+ PRInt32 aStatus,
+ const PRUint8 *aMessage,
+ PRUint32 aLength) {
+ nsresult rv = NS_OK;
+ tmHeader *header = nsnull;
+
+ // indicates the message is the entire raw message
+ if (aQueueID == TM_INVALID_ID) {
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ header = (tmHeader*) RTMemAlloc(aLength);
+#else
+ header = (tmHeader*) malloc(aLength);
+#endif
+ if (header) {
+ mRawMessageLength = aLength;
+ memcpy(header, aMessage, aLength);
+ }
+ else
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ }
+ else { // need to create the tmHeader and concat the message
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ header = (tmHeader*) RTMemAlloc (sizeof(tmHeader) + aLength);
+#else
+ header = (tmHeader*) malloc (sizeof(tmHeader) + aLength);
+#endif
+ if (header) {
+ mRawMessageLength = sizeof(tmHeader) + aLength;
+ header->action = aAction;
+ header->queueID = aQueueID;
+ header->status = aStatus;
+ header->reserved = 0x00000000;
+ if (aLength > 0) // add the message if it exists
+ memcpy((header + 1), aMessage, aLength);
+ }
+ else
+ rv = NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ mOwnerID = aOwnerID;
+ mHeader = header;
+ }
+
+ return rv;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.h
new file mode 100644
index 00000000..b86f20f0
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.h
@@ -0,0 +1,234 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _tmTransaction_H_
+#define _tmTransaction_H_
+
+#include "tmUtils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Message format
+//
+// |------------------------------------|--
+// |QueueID | |
+// |------------------------------------| |
+// | Action - Post/Flush/Attach etc | |- this is the tmHeader struct
+// |------------------------------------| |
+// |Status | |
+// |------------------------------------| |
+// |Padding | |
+// |------------------------------------|--
+// |Message Data (payload) |
+// |------------------------------------|
+//
+// The Attach call is a special case in that it doesn't have a QueueID yet. A
+// QueueID will be 0's. The message Data will be the Queue Name String which
+// will be the profile name with a domain attached, a domain being
+// [prefs|cookies|etc]
+//
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * tmHeader contains various flags identifying
+ */
+struct tmHeader {
+ PRInt32 queueID; // will be the index of the queue in the TM, can be < 0
+ PRUint32 action; // defined by tmUtils.h will be > 0
+ PRInt32 status; // return values from methods, could be < 0
+ PRUint32 reserved; // not currently used, maintaining word alignment
+};
+
+/**
+ * Using tmTransaction:
+ *
+ * After creating a tmTransaction either through new or as a member
+ * or local variable a process must call Init() with the proper set of
+ * arguements to initialize the state of the transaction. tmTransaction is
+ * set up to accept 3 types of initialization.
+ *
+ * 1) Raw message - All data is carried in the byte pointer aMessage,
+ * args 2,3,4 should be set to TM_NO_ID and aLength
+ * must be set to the full length of aMessage, including null
+ * termination if the payload is a null-term string and the size of the
+ * tmHeader struct preceeding the message. Currently this
+ * format is used at the IPC boundary, where we receive a byte pointer
+ * from the IPC Daemon.
+ *
+ * 2) Flags only - aQueueID, aAction and aStatus are all set. aMessage
+ * should be set to nsnull and aLength to 0. This format is used when
+ * sending reply messages (except for ATTACH_REPLY) and when the TS
+ * Transaction Service is sending "control" messages to the Manager -
+ * flush, detach, etc...
+ *
+ * 3) Flags and message - All arguements are set. The aMessage is only
+ * the message for the client app. aLength should be set to the length
+ * of aMessage and not include the length of the tmHeader struct.
+ *
+ * The only data member you can set post initialization is the QueueID.
+ * You should only call Init() once in the lifetime of a tmTransaction
+ * as it doesn't clean up the exisiting data before assigning the new
+ * data. Therefore it would leak most heinously if Init() were to be
+ * called twice.
+ *
+ * mOwnerID only has relevance on the IPC daemon side of things. The
+ * Transaction Service has no knowledge of this ID and makes no use
+ * of it.
+ */
+class tmTransaction
+{
+
+public:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Constructor(s) & Destructor
+
+ tmTransaction(): mHeader(nsnull), mRawMessageLength(0), mOwnerID(0) { }
+
+ virtual ~tmTransaction();
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Public Member Functions
+
+ // Initializer ////////////
+
+ /**
+ * Sets up the internal data of the transaction. Allows for 3 basic ways
+ * to call this function: No flags and just one big raw message, Just
+ * flags and no message, and finally flags and message. If the message
+ * exists it is copied into the transaction.
+ *
+ * @param aOwnerID is given to us by the IPC Daemon and is specific
+ * to that transport layer. It is only set when transactions
+ * are sent from the TM to the TS.
+ *
+ * @param aQueueID is the either the destination queue, or the queue from
+ * where this transaction is eminating
+ *
+ * @param aAction is the action that occured to generate this transaction
+ *
+ * @param aStatus is the success state of the action.
+ *
+ * @param aMessage can be a raw message including the 3 flags above or it
+ * can be just the "payload" of the transaction that the destination
+ * process is going deal with.
+ *
+ * @param aLength is the length of the message. If there is a null
+ * terminated string in the message make sure the length includes
+ * the null termination.
+ *
+ * @returns NS_OK if everything was successful
+ * @returns NS_ERROR_OUT_OF_MEMORY if allocation of space for the
+ * copy of the message fails.
+ */
+ nsresult Init(PRUint32 aOwnerID,
+ PRInt32 aQueueID,
+ PRUint32 aAction,
+ PRInt32 aStatus,
+ const PRUint8 *aMessage,
+ PRUint32 aLength);
+
+ // Data Accessors /////////
+
+ /**
+ * @returns a const byte pointer to the message
+ */
+ const PRUint8* GetMessage() const { return (PRUint8*)(mHeader + 1); }
+
+ /**
+ * @returns the length of the message
+ */
+ PRUint32 GetMessageLength() const {
+ return (mRawMessageLength > sizeof(tmHeader)) ?
+ (mRawMessageLength - sizeof(tmHeader)) : 0;
+ }
+
+ /**
+ * @returns a const pointer to the memory containing the
+ * flag information followed immediately by the message
+ * data.
+ */
+ const PRUint8* GetRawMessage() const { return (PRUint8*) mHeader; }
+
+ /**
+ * @returns the length of the flags and message combined
+ */
+ PRUint32 GetRawMessageLength() const { return mRawMessageLength; }
+
+ /**
+ * @returns the id of the destination or sending queue, depending on the
+ * direction of the transaction.
+ */
+ PRInt32 GetQueueID() const { return mHeader->queueID; }
+
+ /**
+ * @returns the action represented by this transaction
+ */
+ PRUint32 GetAction() const { return mHeader->action; }
+
+ /**
+ * @returns the success state, if applicable of the action leading
+ * up to this message
+ */
+ PRInt32 GetStatus() const { return mHeader->status; }
+
+ /**
+ * @returns the client ID (in IPC daemon terms) of the client who initiated
+ * the exchange that generated this transaction.
+ */
+ PRUint32 GetOwnerID() const { return mOwnerID; }
+
+ // Data Mutator ///////////
+
+ /**
+ * Sets the ID of the destination or source queue. Init should have been
+ * called before the call to this function.
+ */
+ void SetQueueID(PRInt32 aID) { mHeader->queueID = aID; }
+
+protected:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Protected Member Variables
+
+ tmHeader* mHeader; // points to beginning of entire message
+ PRUint32 mRawMessageLength; // length of entire message, incl tmHeader
+ PRUint32 mOwnerID; // client who sent this trans. - a IPC ClientID
+
+};
+
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmUtils.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmUtils.h
new file mode 100644
index 00000000..f85184d3
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmUtils.h
@@ -0,0 +1,93 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _tmUtils_H_
+#define _tmUtils_H_
+
+#include "nscore.h"
+#include "nsError.h"
+#include "nsID.h"
+#include "prlog.h"
+#include <stdio.h>
+
+// UUID used to identify the Transaction Module in both daemon and client
+// not part of the XPCOM hooks, but rather a means of identifying
+// modules withing the IPC daemon.
+#define TRANSACTION_MODULE_ID \
+{ /* c3dfbcd5-f51d-420b-abf4-3bae445b96a9 */ \
+ 0xc3dfbcd5, \
+ 0xf51d, \
+ 0x420b, \
+ {0xab, 0xf4, 0x3b, 0xae, 0x44, 0x5b, 0x96, 0xa9} \
+}
+
+//static const nsID kTransModuleID = TRANSACTION_MODULE_ID;
+
+///////////////////////////////////////////////////////////////////////////////
+// match NS_ERROR_FOO error code formats
+//
+// only create new errors for those errors that are specific to TM
+
+#define NS_ERROR_MODULE_TM 27 /* XXX goes in nserror.h -- integrating with ns error codes */
+
+#define TM_ERROR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 1)
+#define TM_ERROR_WRONG_QUEUE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 2)
+#define TM_ERROR_NOT_POSTED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 3)
+#define TM_ERROR_QUEUE_EXISTS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 4)
+#define TM_SUCCESS_DELETE_QUEUE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 6)
+
+
+// XXX clean up:
+#define TM_INVALID_ID 0xFFFFFFFF
+#define TM_INVALID 0xFFFFFFFF
+#define TM_NO_ID 0xFFFFFFFE
+
+// Transaction Actions
+enum {
+ TM_ATTACH = 0,
+ TM_ATTACH_REPLY,
+ TM_POST,
+ TM_POST_REPLY,
+ TM_NOTIFY,
+ TM_FLUSH,
+ TM_FLUSH_REPLY,
+ TM_DETACH,
+ TM_DETACH_REPLY
+};
+
+#endif
+
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.cpp
new file mode 100644
index 00000000..99213f27
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.cpp
@@ -0,0 +1,179 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include "tmVector.h"
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+# include <iprt/mem.h>
+#endif
+
+////////////////////////////////////////////////////////////////////////////
+// Constructor(s) & Destructor
+
+// can not be responsible for reclaiming memory pointed to by the void*s in
+// the collection - how would we reclaim, don't know how they were allocated
+tmVector::~tmVector() {
+ if (mElements)
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ RTMemFree((void*)mElements);
+#else
+ free((void*)mElements);
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Public Member Functions
+
+nsresult
+tmVector::Init() {
+
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ mElements = (void**) RTMemAllocZ (mCapacity * sizeof(void*));
+#else
+ mElements = (void**) calloc (mCapacity, sizeof(void*));
+#endif
+ if (!mElements)
+ return NS_ERROR_OUT_OF_MEMORY;
+ return NS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// mutators
+
+PRInt32
+tmVector::Append(void *aElement){
+ PR_ASSERT(aElement);
+
+ // make sure there is room
+ if (mNext == mCapacity)
+ if (NS_FAILED(Grow()))
+ return -1;
+
+ // put the element in the array
+ mElements[mNext] = aElement;
+ mCount++;
+
+ // encapsulates the index into a success value
+ return mNext++; // post increment.
+}
+
+void
+tmVector::Remove(void *aElement) {
+ PR_ASSERT(aElement);
+
+ for (PRUint32 index = 0; index < mNext; index++) {
+ if (mElements[index] == aElement) {
+ mElements[index] = nsnull;
+ mCount--;
+ if (index == mNext-1) { // if we removed the last element
+ mNext--;
+ // don't test for success of the shrink
+ Shrink();
+ }
+ }
+ }
+}
+
+void
+tmVector::RemoveAt(PRUint32 aIndex) {
+ PR_ASSERT(aIndex < mNext);
+
+ // remove the element if it isn't already nsnull
+ if (mElements[aIndex] != nsnull) {
+ mElements[aIndex] = nsnull;
+ mCount--;
+ if (aIndex == mNext-1) { // if we removed the last element
+ mNext--;
+ // don't test for success of the shrink
+ Shrink();
+ }
+ }
+}
+
+//void*
+//tmVector::operator[](int index) {
+// if (index < mNext && index >= 0)
+// return mElements[index];
+// return nsnull;
+//}
+
+// Does not delete any of the data, merely removes references to them
+void
+tmVector::Clear(){
+ memset(mElements, 0, mCapacity);
+ mCount = 0;
+ mNext = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Protected Member Functions
+
+// increases the capacity by the growth increment
+nsresult
+tmVector::Grow() {
+
+ PRUint32 newcap = mCapacity + GROWTH_INC;
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ mElements = (void**) RTMemRealloc(mElements, (newcap * sizeof(void*)));
+#else
+ mElements = (void**) realloc(mElements, (newcap * sizeof(void*)));
+#endif
+ if (mElements) {
+ mCapacity = newcap;
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+// reduces the capacity by the growth increment. leaves room
+// for one more add before needing to Grow().
+nsresult
+tmVector::Shrink() {
+
+ PRUint32 newcap = mCapacity - GROWTH_INC;
+ if (mNext < newcap) {
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ mElements = (void**) RTMemRealloc(mElements, newcap * sizeof(void*));
+#else
+ mElements = (void**) realloc(mElements, newcap * sizeof(void*));
+#endif
+ if (!mElements)
+ return NS_ERROR_OUT_OF_MEMORY;
+ mCapacity = newcap;
+ }
+ return NS_OK;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.h
new file mode 100644
index 00000000..4ddb68ef
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.h
@@ -0,0 +1,160 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _tmVector_H_
+#define _tmVector_H_
+
+#include "tmUtils.h"
+
+#define GROWTH_INC 5
+
+/**
+ * A simple, clear, self-growing, collection of objects. typed independant
+ * basically a growing array. Useful in situations where you need an
+ * indexed collection but do not know the size in advance and need the
+ * ability for increase and decrease in size. Not optimized for anything
+ * in particular, or any size in particular.
+ *
+ * Is able to guarantee the index of an item will
+ * not change due to removals of a lower indexed item. The growing,
+ * and shrinking all happens to the end of the collection
+ *
+ * Does not backfill, adds to the end. At some point this should be
+ * changed to make best use of space.
+ */
+class tmVector
+{
+public:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Constructor(s) & Destructor
+
+ /**
+ * Set some sane default values to set up the internal storage. Init()
+ * must be called after construction of the object to allcate the
+ * backing store.
+ */
+ tmVector() : mNext(0), mCount(0), mCapacity(10), mElements(nsnull) {;}
+
+ /**
+ * Reclaim the memory allocated in the Init() method.
+ */
+ virtual ~tmVector();
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Public Member Functions
+
+ /**
+ * Allocates the storage back-end
+ *
+ * @returns NS_OK if allocation succeeded
+ * @returns NS_ERROR_OUT_OF_MEMORY if the allocation failed
+ */
+ nsresult Init();
+
+ // mutators
+
+ /**
+ * @returns the index of the element added, if successful
+ * @returns -1 if an error occured during allocation of space
+ */
+ PRInt32 Append(void *aElement);
+
+ /**
+ * This does not collapse the collection, it leaves holes. Note, it also
+ * doesn't delete the element, it merely removes it from the collection
+ */
+ void Remove(void *aElement);
+
+ /**
+ * This does not collapse the collection, it leaves holes. Note, it also
+ * doesn't delete the element, it merely removes it from the collection
+ */
+ void RemoveAt(PRUint32 aIndex);
+
+ /**
+ * Does not call delete on the elements since we have no idea how to
+ * reclaim the memory. Sets all array slots to 0.
+ */
+ void Clear();
+
+ /**
+ * @returns the element at the index indicated, including nsnull if the
+ * slot is empty.
+ */
+ void* operator[](PRUint32 index) {
+ PR_ASSERT(index < mNext);
+ return mElements[index];
+ }
+
+ /**
+ * @returns the number of elements stored
+ */
+ PRUint32 Count() { return mCount; }
+
+ /**
+ * Meant to be used as the conditional in a loop. |index < size| should
+ * reach all elements of the collection and not run out of bounds. If
+ * slots 0,1,4,5,6 contain elements Size() will return 7, Count() will
+ * return 5.
+ *
+ * @returns the number of slots in the array taken, irrespective of
+ * holes in the collection.
+ */
+ PRUint32 Size() { return mNext; }
+
+protected:
+
+ nsresult Grow(); // mCapacity += GROWTH_INC - realloc()s
+ nsresult Shrink(); // mCapacity -= GROWTH_INC - dumb, free, malloc
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Protected Member Variables
+
+ // bookkeeping variables
+ PRUint32 mNext; // next element insertion slot (0 based)
+ PRUint32 mCount; // how many elements in the Vector (1 based)
+ PRUint32 mCapacity; // current capacity of the Vector (1 based)
+
+ // the actual array of objects being stored
+ void **mElements;
+
+private:
+
+};
+
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/.cvsignore
new file mode 100644
index 00000000..ccfb2bc3
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/.cvsignore
@@ -0,0 +1,11 @@
+Makefile
+module.rc
+module.res
+tmIPCModule.obj
+tmQueue.obj
+tmTransactionManager.obj
+transmgr.dll
+transmgr.exp
+transmgr.ilk
+transmgr.lib
+transmgr.pdb
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/Makefile.in
new file mode 100644
index 00000000..b8baa225
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/Makefile.in
@@ -0,0 +1,100 @@
+# ***** 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 Transaction Manager.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corp.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# John Gaunt <jgaunt@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+LIBRARY_NAME = transmgr
+MODULE_NAME = ipcd
+
+FORCE_SHARED_LIB = 1
+NO_DIST_INSTALL = 1
+NO_INSTALL = 1
+
+ifeq ($(OS_ARCH),Darwin)
+NO_COMPONENT_LINK_MAP = 1
+MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS =
+endif
+
+REQUIRES = nspr \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = \
+ tmIPCModule.cpp \
+ tmQueue.cpp \
+ tmTransactionManager.cpp \
+ $(NULL)
+
+EXPORTS = \
+ tmIPCModule.h \
+ $(NULL)
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/../common \
+ $(NULL)
+
+include $(topsrcdir)/config/config.mk
+
+LIBS = \
+ $(EXTRA_DSO_LIBS) \
+ $(NSPR_LIBS) \
+ $(NULL)
+
+EXTRA_DSO_LDOPTS = \
+ $(LIBS_DIR) \
+ $(NSPR_LIBS) \
+ $(DIST)/lib/$(LIB_PREFIX)transmgrcom_s.$(LIB_SUFFIX) \
+ $(EXTRA_DSO_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+_IPC_FILES = \
+ $(DLL_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/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.cpp
new file mode 100644
index 00000000..3982c93c
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.cpp
@@ -0,0 +1,137 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "tmIPCModule.h"
+#include "tmTransaction.h"
+#include "tmTransactionManager.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// IPC Daemon hookup stuff
+
+// functionpointer array giving access to this module from the IPC daemon
+static ipcModuleMethods gTransMethods =
+{
+ IPC_MODULE_METHODS_VERSION,
+ tmIPCModule::Init,
+ tmIPCModule::Shutdown,
+ tmIPCModule::HandleMsg
+};
+
+static ipcModuleEntry gTransModuleEntry[] =
+{
+ { TRANSACTION_MODULE_ID, &gTransMethods }
+};
+
+IPC_IMPL_GETMODULES(TransactionModule, gTransModuleEntry)
+
+static const nsID kTransModuleID = TRANSACTION_MODULE_ID;
+
+///////////////////////////////////////////////////////////////////////////////
+// Define global variable
+
+tmTransactionManager *tmIPCModule::tm;
+
+///////////////////////////////////////////////////////////////////////////////
+// IPC Module API
+
+void
+tmIPCModule::Init() {
+ if (!tm)
+ InitInternal();
+}
+
+void
+tmIPCModule::Shutdown() {
+ if (tm) {
+ delete tm;
+ tm = nsnull;
+ }
+}
+
+// straight pass-through, don't check args, let the TM do it.
+void
+tmIPCModule::HandleMsg(ipcClientHandle client, const nsID &target,
+ const void *data, PRUint32 dataLen) {
+
+ // make sure the trans mngr is there
+ if (!tm && (InitInternal() < 0))
+ return;
+
+ // create the transaction
+ tmTransaction *trans = new tmTransaction();
+
+ // initialize it
+ if (trans) {
+ if(NS_SUCCEEDED(trans->Init(IPC_GetClientID(client), // who owns it
+ TM_INVALID_ID, // in data
+ TM_INVALID, // in data
+ TM_INVALID, // in data
+ (PRUint8 *)data, // raw message
+ dataLen))) { // length of message
+ // pass it on to the trans mngr
+ tm->HandleTransaction(trans);
+ }
+ else
+ delete trans;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// tmIPCModule API
+
+// straight pass-through, don't check args, let the TS & TM do it.
+void
+tmIPCModule::SendMsg(PRUint32 aDestClientIPCID, tmTransaction *aTransaction) {
+
+ IPC_SendMsg(aDestClientIPCID,
+ kTransModuleID,
+ (void *)aTransaction->GetRawMessage(),
+ aTransaction->GetRawMessageLength());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Protected Methods
+
+PRInt32
+tmIPCModule::InitInternal() {
+
+ tm = new tmTransactionManager();
+ if (tm)
+ return tm->Init();
+ return -1;
+}
+
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.h
new file mode 100644
index 00000000..d4623b1e
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.h
@@ -0,0 +1,109 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _tmIPCModule_H_
+#define _tmIPCModule_H_
+
+#include "ipcModuleUtil.h"
+#include "tmUtils.h"
+
+// forward declarations
+class tmTransaction;
+class tmTransactionManager;
+
+/**
+ * Basically an interface between the tmTransactionManager and the IPC
+ * daemon. Does little else than format the data from one party into
+ * a format understandable to the other.
+ *
+ * The reason for this class is to try and abstract the transportation
+ * layer the transaction service uses. By using this class the Transaction
+ * Manager itself only needs to know that clients are identified by
+ * PRUint32 IDs.
+ */
+class tmIPCModule
+{
+public:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // ipcModule API - called from IPC daemon
+
+ /**
+ * Clean up the TM
+ */
+ static void Shutdown();
+
+ /**
+ * Check the TM, create it if neccessary.
+ */
+ static void Init();
+
+ /**
+ * Receives a message from the IPC daemon, creates a transaction and sends
+ * it to the TM to deal with.
+ */
+ static void HandleMsg(ipcClientHandle client,
+ const nsID &target,
+ const void *data,
+ PRUint32 dataLen);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // tmIPCModule API - called from tmTransactionManager
+
+ /**
+ * Sends the message to the IPC daemon to be deliverd to the client arg.
+ */
+ static void SendMsg(PRUint32 aDestClientIPCID, tmTransaction *aTransaction);
+
+protected:
+
+ /**
+ * tm should be null coming into this method. This does NOT delete tm
+ * first.
+ *
+ * @returns NS_OK if everything succeeds
+ * @returns -1 if initialization fails
+ */
+ static PRInt32 InitInternal();
+
+ static tmTransactionManager *tm;
+
+};
+
+#endif
+
+
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.cpp
new file mode 100644
index 00000000..5164446f
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.cpp
@@ -0,0 +1,223 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "plstr.h"
+#include "tmQueue.h"
+#include "tmTransaction.h"
+#include "tmTransactionManager.h"
+#include "tmUtils.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors & Destructor
+
+tmQueue::~tmQueue() {
+
+ // empty the vectors
+ PRUint32 index = 0;
+ PRUint32 size = mTransactions.Size();
+ for ( ; index < size ; index++) {
+ if (mTransactions[index])
+ delete (tmTransaction *)mTransactions[index];
+ }
+
+ // don't need to delete the mListeners because
+ // we just insert PRUint32s, no allocation
+
+ mTM = nsnull;
+ mID = 0;
+ if (mName)
+ PL_strfree(mName);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Public Methods
+
+PRInt32
+tmQueue::Init(const char* aName, PRUint32 aID, tmTransactionManager *aTM) {
+ PR_ASSERT(mTM == nsnull);
+
+ if (NS_SUCCEEDED(mTransactions.Init()) &&
+ NS_SUCCEEDED(mListeners.Init()) &&
+ ((mName = PL_strdup(aName)) != nsnull) ) {
+ mTM = aTM;
+ mID = aID;
+ return NS_OK;
+ }
+ return -1;
+}
+
+PRInt32
+tmQueue::AttachClient(PRUint32 aClientID) {
+
+ PRInt32 status = NS_OK; // success of adding client
+
+ if (!IsAttached(aClientID)) {
+ // add the client to the listener list -- null safe call
+ status = mListeners.Append((void*) aClientID);
+ }
+ else
+ status = -2;
+
+ // create & init a reply transaction
+ tmTransaction trans;
+ if (NS_SUCCEEDED(trans.Init(aClientID, // owner's ipc ID
+ mID, // client gets our ID
+ TM_ATTACH_REPLY, // action
+ status, // success of the add
+ (PRUint8*)mName, // client matches name to ID
+ PL_strlen(mName)+1))) {
+ // send the reply
+ mTM->SendTransaction(aClientID, &trans);
+ }
+
+ // if we successfully added the client - send all current transactions
+ if (status >= 0) { // append returns the index of the added element
+
+ PRUint32 size = mTransactions.Size();
+ for (PRUint32 index = 0; index < size; index++) {
+ if (mTransactions[index])
+ mTM->SendTransaction(aClientID, (tmTransaction*) mTransactions[index]);
+ }
+ }
+ return status;
+}
+
+PRInt32
+tmQueue::DetachClient(PRUint32 aClientID) {
+
+ PRUint32 size = mListeners.Size();
+ PRUint32 id = 0;
+ PRInt32 status = -1;
+
+ for (PRUint32 index = 0; index < size; index++) {
+ id = (PRUint32)NS_PTR_TO_INT32(mListeners[index]);
+ if(id == aClientID) {
+ mListeners.RemoveAt(index);
+ status = NS_OK;
+ break;
+ }
+ }
+
+ tmTransaction trans;
+ if (NS_SUCCEEDED(trans.Init(aClientID,
+ mID,
+ TM_DETACH_REPLY,
+ status,
+ nsnull,
+ 0))) {
+ // send the reply
+ mTM->SendTransaction(aClientID, &trans);
+ }
+
+ // if we've removed all the listeners, remove the queue.
+ if (mListeners.Size() == 0)
+ return TM_SUCCESS_DELETE_QUEUE;
+ return status;
+}
+
+void
+tmQueue::FlushQueue(PRUint32 aClientID) {
+
+ if(!IsAttached(aClientID))
+ return;
+
+ PRUint32 size = mTransactions.Size();
+ for (PRUint32 index = 0; index < size; index++)
+ if (mTransactions[index])
+ delete (tmTransaction*)mTransactions[index];
+
+ mTransactions.Clear();
+
+ tmTransaction trans;
+ if (NS_SUCCEEDED(trans.Init(aClientID,
+ mID,
+ TM_FLUSH_REPLY,
+ NS_OK,
+ nsnull,
+ 0))) {
+ mTM->SendTransaction(aClientID, &trans);
+ }
+}
+
+PRInt32
+tmQueue::PostTransaction(tmTransaction *aTrans) {
+
+ PRInt32 status = -1;
+ PRUint32 ownerID = aTrans->GetOwnerID();
+
+ // if we are attached, have the right queue and have successfully
+ // appended the transaction to the queue, send the transaction
+ // to all the listeners.
+
+ if (IsAttached(ownerID) && aTrans->GetQueueID() == mID)
+ status = mTransactions.Append(aTrans);
+
+ if (status >= 0) {
+ // send the transaction to all members of mListeners except the owner
+ PRUint32 size = mListeners.Size();
+ PRUint32 id = 0;
+ for (PRUint32 index = 0; index < size; index++) {
+ id = (PRUint32)NS_PTR_TO_INT32(mListeners[index]);
+ if (ownerID != id)
+ mTM->SendTransaction(id, aTrans);
+ }
+ }
+
+ tmTransaction trans;
+ if (NS_SUCCEEDED(trans.Init(ownerID,
+ mID,
+ TM_POST_REPLY,
+ status,
+ nsnull,
+ 0))) {
+ // send the reply
+ mTM->SendTransaction(ownerID, &trans);
+ }
+ return status;
+}
+
+PRBool
+tmQueue::IsAttached(PRUint32 aClientID) {
+ // XXX could be an issue if the aClientID is 0 and there
+ // is a "hole" in the mListeners vector. - may NEED to store PRUint32*s
+ PRUint32 size = mListeners.Size();
+ for (PRUint32 index = 0; index < size; index++) {
+ if (aClientID == (PRUint32)NS_PTR_TO_INT32(mListeners[index]))
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.h
new file mode 100644
index 00000000..1c680084
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.h
@@ -0,0 +1,186 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _tmQueue_H_
+#define _tmQueue_H_
+
+#include "tmUtils.h"
+#include "tmVector.h"
+
+class tmClient;
+class tmTransaction;
+class tmTransactionManager;
+
+/**
+ * This class isn't so much a queue as it is storage for transactions. It
+ * is set up to recieve and store transactions in a growing collection
+ * (using tmVectors). Different messages can be recieved from the
+ * Transaction Manager(TM) the queue belongs to which can add and remove
+ * listeners, empty the queue (flush), and add messages to the queue.
+ *
+ * See the documentation in tmTransactionService.h for details on the
+ * messages you can send to and recieve from the queues in the TM
+ */
+class tmQueue
+{
+
+public:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Constructor & Destructor
+
+ /**
+ * Set the internal state to default values. Init() must be called
+ * after construction to allocate the storage and set the name and ID.
+ */
+ tmQueue(): mID(0), mName(nsnull), mTM(nsnull) { }
+
+ /**
+ * Reclaim the memory allocated in Init(). Destroys the transactions in
+ * the transaction storage and the ids in the listener storage
+ */
+ virtual ~tmQueue();
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Public Member Functions
+
+ /**
+ * Initialize internal storage vectors and set the name of the queue
+ * and the pointer to the TM container.
+ *
+ * @returns NS_OK if everything succeeds
+ * @returns -1 if initialization fails
+ */
+ PRInt32 Init(const char* aName, PRUint32 aID, tmTransactionManager *aTM);
+
+ // Queue Operations
+
+ /**
+ * Adds the clientID to the list of queue listeners. A reply is created
+ * and sent to the client. The reply contains both the name of the
+ * queue and the id, so the client can match the id to the name and
+ * then use the id in all further communications to the queue. All
+ * current transactions in the queue are then sent to the client.
+ *
+ * If the client was already attached the reply is sent, but not the
+ * outstanding transactions, the assumption being made that all
+ * transactions have already been sent to the client.
+ *
+ * The reply is sent for all cases, with the return value in the status
+ * field.
+ *
+ * @returns >= 0 if the client was attached successfully
+ * @returns -1 if the client was not attached
+ * @returns -2 if the client was already attached
+ */
+ PRInt32 AttachClient(PRUint32 aClientID);
+
+ /**
+ * Removes the client from the list of queue listeners. A reply is created
+ * and sent to the client to indicate the success of the removal.
+ *
+ * The reply is sent for all cases, with the status field set to either
+ * -1 or NS_OK.
+ *
+ * @returns NS_OK on success
+ * @returns -1 if client is not attached to this queue
+ * @returns TM_SUCCESS_DELETE_QUEUE if there are no more listeners,
+ * instructing the Transaction Mangaer to delete the queue.
+ */
+ PRInt32 DetachClient(PRUint32 aClientID);
+
+ /**
+ * Removes all the transactions being held in the queue.
+ * A reply is created and sent to the client to indicate the
+ * completion of the operation.
+ */
+ void FlushQueue(PRUint32 aClientID);
+
+ /**
+ * Places the transaction passed in on the queue. Takes ownership of the
+ * transaction, deletes it in the destructor. A reply is created and
+ * sent to the client to indicate the success of the posting of the
+ * transaction.
+ *
+ * The reply is sent for all cases, with the status field containing the
+ * return value.
+ *
+ * @returns >= 0 if the message was posted properly.
+ * @returns -1 if the client posting is not attached to this queue,
+ * if the transaction has been posted to the wrong queue or
+ * if an error occured when trying to add the post to the
+ * internal storage.
+ */
+ PRInt32 PostTransaction(tmTransaction *aTrans);
+
+ // Accessors
+
+ /**
+ * @returns the ID of the queue
+ */
+ PRUint32 GetID() const { return mID; }
+
+ /**
+ * @returns the name of the queue
+ */
+ const char* GetName() const { return mName; }
+
+protected:
+
+ /**
+ * Helper method to determine if the client has already attached.
+ *
+ * @returns PR_TRUE if the client is attached to the queue.
+ * @returns PR_FALSE if the client is not attached to the queue.
+ */
+ PRBool IsAttached(PRUint32 aClientID);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Protected Member Variables
+
+ // storage
+ tmVector mTransactions; // transactions that have been posted
+ tmVector mListeners; // programs listening to this queue
+
+ // bookkeeping
+ PRUint32 mID; // a number linked to the name in the mTM
+ char *mName; // format: [namespace][domainname(ie prefs)]
+ tmTransactionManager *mTM; // the container that holds the queue
+
+};
+
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.cpp
new file mode 100644
index 00000000..9d6cc98e
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.cpp
@@ -0,0 +1,162 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "plstr.h"
+#include <stdlib.h>
+#include "tmQueue.h"
+#include "tmTransactionManager.h"
+#include "tmTransaction.h"
+#include "tmUtils.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors & Destructor & Initializer
+
+tmTransactionManager::~tmTransactionManager() {
+
+ PRUint32 size = mQueues.Size();
+ tmQueue *queue = nsnull;
+ for (PRUint32 index = 0; index < size; index++) {
+ queue = (tmQueue *)mQueues[index];
+ if (queue) {
+ delete queue;
+ }
+ }
+}
+
+PRInt32
+tmTransactionManager::Init() {
+ return mQueues.Init();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// public transaction module methods
+
+void
+tmTransactionManager::HandleTransaction(tmTransaction *aTrans) {
+
+ PRUint32 action = aTrans->GetAction();
+ PRUint32 ownerID = aTrans->GetOwnerID();
+ tmQueue *queue = nsnull;
+
+ // get the right queue -- attaches do it differently
+ if (action == TM_ATTACH) {
+ const char *name = (char*) aTrans->GetMessage(); // is qName for Attaches
+ queue = GetQueue(name);
+ if (!queue) {
+ PRInt32 index = AddQueue(name);
+ if (index >= 0)
+ queue = GetQueue(index); // GetQueue may return nsnull
+ }
+ }
+ else // all other trans should have a valid queue ID already
+ queue = GetQueue(aTrans->GetQueueID());
+
+ if (queue) {
+ // All possible actions should have a case, default is not valid
+ // delete trans when done with them, let the queue own the trans
+ // that are posted to them.
+ PRInt32 result = 0;
+ switch (action) {
+ case TM_ATTACH:
+ queue->AttachClient(ownerID);
+ break;
+ case TM_POST:
+ result = queue->PostTransaction(aTrans);
+ if (result >= 0) // post failed, aTrans cached in a tmQueue
+ return;
+ break;
+ case TM_FLUSH:
+ queue->FlushQueue(ownerID);
+ break;
+ case TM_DETACH:
+ if (queue->DetachClient(ownerID) == TM_SUCCESS_DELETE_QUEUE) {
+ // the last client has been removed, remove the queue
+ RemoveQueue(aTrans->GetQueueID()); // this _could_ be out of bounds
+ }
+ break;
+ default:
+ PR_NOT_REACHED("bad action in the transaction");
+ }
+ }
+ delete aTrans;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Protected member functions
+
+//
+// Queue Handling
+//
+
+tmQueue*
+tmTransactionManager::GetQueue(const char *aQueueName) {
+
+ PRUint32 size = mQueues.Size();
+ tmQueue *queue = nsnull;
+ for (PRUint32 index = 0; index < size; index++) {
+ queue = (tmQueue*) mQueues[index];
+ if (queue && strcmp(queue->GetName(), aQueueName) == 0)
+ return queue;
+ }
+ return nsnull;
+}
+
+// if successful the nsresult contains the index of the added queue
+PRInt32
+tmTransactionManager::AddQueue(const char *aQueueName) {
+
+ tmQueue* queue = new tmQueue();
+ if (!queue)
+ return -1;
+ PRInt32 index = mQueues.Append(queue);
+ if (index < 0)
+ delete queue;
+ else
+ queue->Init(aQueueName, index, this);
+ return index;
+}
+
+void
+tmTransactionManager::RemoveQueue(PRUint32 aQueueID) {
+ PR_ASSERT(aQueueID <= mQueues.Size());
+
+ tmQueue *queue = (tmQueue*)mQueues[aQueueID];
+ if (queue) {
+ mQueues.RemoveAt(aQueueID);
+ delete queue;
+ }
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.h
new file mode 100644
index 00000000..a03ba528
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.h
@@ -0,0 +1,147 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _tmTransactionManager_H_
+#define _tmTransactionManager_H_
+
+#include "plhash.h"
+#include "tmUtils.h"
+#include "tmVector.h"
+#include "tmIPCModule.h"
+
+// forward declarations
+class tmQueue;
+class tmClient;
+class tmTransaction;
+
+/**
+ * This class manages the flow of messages from the IPC daemon (coming to
+ * it through the tmIPCModule) that ultimately come from a Transaction
+ * Service (TS) in a mozilla based client somewhere. The message is
+ * delivered to the proper queue, where it is dealt with.
+ *
+ * New queues get created here as clients request them.
+ */
+class tmTransactionManager
+{
+
+public:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Constructor(s) & Destructor & Initializer
+
+ /**
+ * reclaim the memory allcoated during initialization
+ */
+ virtual ~tmTransactionManager();
+
+ /**
+ * Set up the storage of the queues - initialize the vector
+ *
+ * @returns NS_OK if successful
+ * @returns -1 if initialization fails
+ */
+ PRInt32 Init();
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Public Member Functions
+
+ /**
+ * Called from the tmIPCModule. Decide where to send the message and
+ * dispatch it.
+ */
+ void HandleTransaction(tmTransaction *aTrans);
+
+ /**
+ * Called by the queues when they need to get a message back out to a
+ * client.
+ */
+ void SendTransaction(PRUint32 aDestClientIPCID, tmTransaction *aTrans) {
+ PR_ASSERT(aTrans);
+ tmIPCModule::SendMsg(aDestClientIPCID, aTrans);
+ }
+
+protected:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Protected Member Functions
+
+ // Queue management
+
+ /**
+ * @returns the queue indexed by the ID passed in, which could be nsnull
+ */
+ tmQueue* GetQueue(PRUint32 aQueueID) {
+ return (tmQueue*) mQueues[aQueueID];
+ }
+
+ /**
+ * @returns the queue with the name passed in
+ * @returns nsnull if there is no queue with that name
+ */
+ tmQueue* GetQueue(const char *aQueueName);
+
+ /**
+ * If all is successful a new queue with the name provided will be created,
+ * and added to the collection of queues. It will be initialized and ready
+ * to have transactions added.
+ *
+ * This doesn't check for the existance of a queue with this name. IF
+ * there is already a queue with this name then you will
+ * get that when using GetQueue(qName) and never get the new queue
+ * created here. A call to GetQueue(qID) will be able to get at the new
+ * queue, however you had better cache the ID.
+ *
+ * @returns -1 if the queue can't be created, or is not added
+ * @returns >= 0 if the queue was added successfully
+ */
+ PRInt32 AddQueue(const char *aQueueType);
+
+ /**
+ */
+ void RemoveQueue(PRUint32 aQueueID);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Protected Member Variables
+
+ tmVector mQueues;
+
+private:
+
+};
+
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/Makefile.in
new file mode 100644
index 00000000..65b126e9
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/Makefile.in
@@ -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 Transaction Manager.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corp.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# John Gaunt <jgaunt@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+XPIDL_MODULE = ipcd_transmngr
+
+XPIDLSRCS = \
+ ipcITransactionService.idl \
+ ipcITransactionObserver.idl \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl
new file mode 100644
index 00000000..c7df965d
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl
@@ -0,0 +1,100 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(656c0a6a-5cb3-45ec-8cb6-e7678897f937)]
+interface ipcITransactionObserver : nsISupports
+{
+ /**
+ * This gets called when a Transaction has been sent from the
+ * TransactionManager. If the data passed in needs to be stored
+ * for longer than the life of the method the observer needs
+ * to make a copy.
+ *
+ * @param aQueueID
+ * The queue from which the transaction originated
+ *
+ * @param aData
+ * The data to be sent.
+ *
+ * @param aDataLen
+ * The length of the data argument
+ */
+ void onTransactionAvailable(in unsigned long aQueueID,
+ [array, const, size_is(aDataLen)]
+ in octet aData,
+ in unsigned long aDataLen);
+
+ /**
+ * Called after an application sends an Attach message to the
+ * Transaction Manager.
+ *
+ * @param aQueueID
+ * The client has been attached to the queue with this ID
+ *
+ * @param aStatus
+ * The status of the operation, as defined in tmUtils.h
+ */
+ void onAttachReply(in unsigned long aQueueID, in unsigned long aStatus);
+
+ /**
+ * Called after an application sends a Detach message. Indicates
+ * to the client that no more messages will be coming from the
+ * the TM to this client. Also, no messages posted from this
+ * client to the indicated queue will be accepted.
+ *
+ * @param aQueueID
+ * The client has been detached from the queue with this ID
+ *
+ * @param aStatus
+ * The status of the operation, as defined in tmUtils.h
+ */
+ void onDetachReply(in unsigned long aQueueID, in unsigned long aStatus);
+
+ /**
+ * The reply from the TM indicating all messages have been removed
+ * from the queue indicated.
+ *
+ * @param aQueueID
+ * The queue that has been flushed.
+ *
+ * @param aStatus
+ * The status of the operation, as defined in tmUtils.h
+ */
+ void onFlushReply(in unsigned long aQueueID, in unsigned long aStatus);
+};
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl
new file mode 100644
index 00000000..0bcbc453
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl
@@ -0,0 +1,239 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// from tmTransactionManager.h
+//
+// XXX documentation needs work
+//////////////////////////////////////////////////////////////////////////////
+// Overview of TransactionManager IPC Module
+//
+// Classes:
+// tmIPCModule - From the tmTransactionManager's point of view, this
+// is a proxy for the IPC daemon itself. The reverse is true
+// from the daemon's point of view. This is an interface for the
+// Transaction system to work with the IPC daemon as its transport
+// layer.
+// tmTransactionManager (TM) - Manages the different queues. Maintains
+// the queues neccessary for different clients. Receives messages
+// from the tmIPCModule and passes message to the IPC daemon through
+// the tmIPCModule.
+// tmQueue - this class manages the transactions for the different areas
+// of the profiles being shared. Broken down by functional area there
+// will be a queue for prefs, cookies etc, but not for profileA and
+// profileB, and not for pref_delete, pref_create, pref_change etc...
+// tmTransaction - the actual transaction being shared with the different
+// tmClients. It contains the type of transaction, which will equate with
+// a type of queue in existance, the owner of the transaction (an IPC daemon ID)
+// and the actual text message to be shared.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+/// XXX some docs that need to be put somewhere:
+//
+// from tmqueue.cpp
+// Docs - note that the status of the TM_ATTACH_REPLY is only for checking
+// for TM_ERROR_FAILURE. Other numbers have no importance
+// success of the status means the NS_ERROR_GET_CODE(status) will
+// yield the index of the listener.
+//
+// move to documentation page - from tmqueue.h
+//
+// a queue is specific to profile
+//
+// UUID going out from the module is a handler in the client
+// (will go to the XPCOM service impling that UUID)
+// -- does it make sense to have different UUIDs for cookies/prefs/etc
+//
+
+#include "nsISupports.idl"
+
+interface ipcITransactionObserver;
+
+[scriptable, uuid(15561efb-8c58-4a47-813a-fa91cf730895)]
+interface ipcITransactionService : nsISupports
+{
+ /**
+ * Connects the application to the transaction manager, defines the
+ * namespace and initializes internal storage
+ *
+ * @param aNamespace
+ * A string defining the scope of the transaction domains. It is
+ * used internally to seperate process listening to the same domain
+ * (ie. preferences) but for two different namespaces (ie. profile1 vs
+ * profile2).
+ *
+ * @returns NS_OK if all memory allocated properly and the IPC service was
+ * reached and attached to successfully.
+ *
+ * @returns an NS_ERROR_<foo> code specific to the failure otherwise
+ */
+ void init(in ACString aNamespace);
+
+ /**
+ * Links the observer passed in with the domain specified. This will allow
+ * the observer to post transactions dealing with this domain as well as
+ * receive transactions posted by other applications observing this
+ * domain.
+ *
+ * Return codes for this method confer information about the success of
+ * this call, not of the actual attaching of the observer to the domain.
+ * (except the TM_ERROR code - which means the observer can not attach)
+ * If the attach is successful the observer will have its OnAttachReply
+ * method called before this method returns.
+ *
+ * Note: This call is synchronous and will not return until the call to
+ * OnAttachReply is made.
+ *
+ * @param aDomainName
+ * the name of the domain, in the current namespace, to listen for
+ * transactions from. i.e. cookies
+ *
+ * @param aObserver
+ * this will be used to notify the application when transactions
+ * and messages come in.
+ *
+ * @param aLockingCall
+ * Have the Transaction Sevice acquire a lock based on the domain
+ * before attaching. This should be used when persistant storage
+ * is being used to prevent data corruption.
+ *
+ * @returns NS_OK if the attach message was sent to the Transaction Manager.
+ *
+ * @returns an NS_ERROR_<foo> code specific to the failure otherwise
+ *
+ * @returns TM_ERROR_QUEUE_EXISTS if the queue already exists which means
+ * someone has already attached to it.
+ */
+ void attach(in ACString aDomainName,
+ in ipcITransactionObserver aObserver,
+ in PRBool aLockingCall);
+
+ /**
+ * Sends a detach message to the Transaction Manager to unlink the observer
+ * associated with the domain passed in.
+ *
+ * As in attach, return codes do not indicate success of detachment. The
+ * observer will have it's OnDetach method called if it is successfully
+ * detached.
+ *
+ * Note: This call is an asynchronous call.
+ *
+ * @param aDomainName
+ * the domain, in the current namespace, from which the client
+ * should be removed.
+ *
+ * @returns NS_OK if the detach message is sent to the Transaction Manager
+ *
+ * @returns NS_ERROR_FAILURE is something goes wrong
+ *
+ * @returns NS_ERRROR_UNEXPECTD if the domain does not have an observer
+ * attached
+ */
+ void detach(in ACString aDomainName);
+
+ /**
+ * Sends a flush message to the Transaction Manager to remove all
+ * transactions for the domain. After this call there will be no
+ * transactions in the Transaction Manager for the namespace/domain
+ * pairing. It is up to the application to coordinate the flushing
+ * of the Transaction Manager with the writing of data to files,
+ * if needed.
+ *
+ * Note: This call is synchronous and will not return until the call to
+ * OnFlushReply is made.
+ *
+ * @param aDomainName
+ * The domain, in the current namespace, to flush.
+ *
+ * @param aLockingCall
+ * Have the Transaction Sevice acquire a lock based on the domain
+ * before flushing. This should be used when persistant storage
+ * is being used to prevent data corruption.
+ *
+ * @returns NS_OK if the flush message is sent to the Transaction Manager
+ *
+ * @returns NS_ERROR_FAILURE is something goes wrong
+ *
+ * @returns NS_ERRROR_UNEXPECTD if the domain does not have an observer
+ * attached
+ */
+ void flush(in ACString aDomainName, in PRBool aLockingCall);
+
+ /**
+ * Send the data to the Transaction Manager to be broadcast to any
+ * applications that have registered as observers of this particular
+ * namespace/domain pairing.
+ *
+ * If this domain is not being observed (attach has not been called for
+ * this domain) the message is queued until the attach is made and then
+ * the message is sent to the Transaction Manager with the proper domain
+ * information.
+ *
+ * XXXjg - this may not be neccessary with the synch attach call.
+ *
+ * Note: This call is an asynchronous call.
+ *
+ * @param aDomainName
+ * the domain, in the current namespace, to which the data will be
+ * sent.
+ *
+ * @param aData
+ * The actual data to be sent.
+ *
+ * @param aDataLen
+ * The length of the data argument
+ */
+ void postTransaction(in ACString aDomainName,
+ [array, const, size_is(aDataLen)]
+ in octet aData,
+ in unsigned long aDataLen);
+};
+
+%{C++
+// singleton implementing ipcITransactionService
+#define IPC_TRANSACTIONSERVICE_CLASSNAME \
+ "tmTransactionService"
+#define IPC_TRANSACTIONSERVICE_CONTRACTID \
+ "@mozilla.org/ipc/transaction-service;1"
+#define IPC_TRANSACTIONSERVICE_CID \
+{ /* 1403adf4-94d1-4c67-a8ae-d9f86972d378 */ \
+ 0x1403adf4, \
+ 0x94d1, \
+ 0x4c67, \
+ {0xa8, 0xae, 0xd9, 0xf8, 0x69, 0x72, 0xd3, 0x78} \
+}
+%}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/.cvsignore
new file mode 100644
index 00000000..7726b497
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/.cvsignore
@@ -0,0 +1,4 @@
+Makefile
+tmTransactionService.obj
+transmgr_s.lib
+transmgr_s.pdb \ No newline at end of file
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/Makefile.in
new file mode 100644
index 00000000..6510e489
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/Makefile.in
@@ -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 Transaction Manager.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corp.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# John Gaunt <jgaunt@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+LIBRARY_NAME = transmgr_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME = ipcd
+
+REQUIRES = string \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = \
+ tmTransactionService.cpp \
+ $(NULL)
+
+include $(topsrcdir)/config/config.mk
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/../common \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp
new file mode 100644
index 00000000..e53d6aa7
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp
@@ -0,0 +1,504 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsCOMPtr.h"
+#include "nsIServiceManager.h"
+#include "nsReadableUtils.h"
+#include "plstr.h"
+#include "ipcITransactionObserver.h"
+#include "tmTransaction.h"
+#include "tmTransactionService.h"
+#include "tmUtils.h"
+
+static const nsID kTransModuleID = TRANSACTION_MODULE_ID;
+
+struct tm_waiting_msg {
+ tmTransaction trans; // a transaction waiting to be sent to a queue
+ char* domainName; // the short queue name
+
+ ~tm_waiting_msg();
+};
+
+tm_waiting_msg::~tm_waiting_msg() {
+ if (domainName)
+ PL_strfree(domainName);
+}
+
+struct tm_queue_mapping {
+ PRInt32 queueID; // the ID in the TM
+ char* domainName; // used by the consumers of this service
+ char* joinedQueueName; // used by the service -- namespace + domain name
+
+ ~tm_queue_mapping();
+};
+
+tm_queue_mapping::~tm_queue_mapping() {
+ if (domainName)
+ PL_strfree(domainName);
+ if (joinedQueueName)
+ PL_strfree(joinedQueueName);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Constructor and Destructor
+
+tmTransactionService::~tmTransactionService() {
+
+ // just destroy this, it contains 2 pointers it doesn't own.
+ if (mObservers)
+ PL_HashTableDestroy(mObservers);
+
+ PRUint32 index = 0;
+ PRUint32 size = mWaitingMessages.Size();
+ tm_waiting_msg *msg = nsnull;
+ for ( ; index < size; index ++) {
+ msg = (tm_waiting_msg*) mWaitingMessages[index];
+ delete msg;
+ }
+
+ size = mQueueMaps.Size();
+ tm_queue_mapping *qmap = nsnull;
+ for (index = 0; index < size; index++) {
+ qmap = (tm_queue_mapping*) mQueueMaps[index];
+ if (qmap)
+ delete qmap;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// ISupports
+
+NS_IMPL_ISUPPORTS2(tmTransactionService,
+ ipcITransactionService,
+ ipcIMessageObserver)
+
+//////////////////////////////////////////////////////////////////////////////
+// ipcITransactionService
+
+NS_IMETHODIMP
+tmTransactionService::Init(const nsACString & aNamespace) {
+
+ nsresult rv;
+
+ rv = IPC_DefineTarget(kTransModuleID, this, PR_TRUE);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // get the lock service
+ lockService = do_GetService("@mozilla.org/ipc/lock-service;1");
+ if (!lockService)
+ return NS_ERROR_FAILURE;
+
+ // create some internal storage
+ mObservers = PL_NewHashTable(20,
+ PL_HashString,
+ PL_CompareStrings,
+ PL_CompareValues, 0, 0);
+ if (!mObservers)
+ return NS_ERROR_FAILURE;
+
+ // init some internal storage
+ mQueueMaps.Init();
+ mWaitingMessages.Init();
+
+ // store the namespace
+ mNamespace.Assign(aNamespace);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+tmTransactionService::Attach(const nsACString & aDomainName,
+ ipcITransactionObserver *aObserver,
+ PRBool aLockingCall) {
+
+ // if the queue already exists, then someone else is attached to it. must
+ // return an error here. Only one module attached to a queue per app.
+ if (GetQueueID(aDomainName) != TM_NO_ID)
+ return TM_ERROR_QUEUE_EXISTS;
+
+ // create the full queue name: namespace + queue
+ nsCString jQName;
+ jQName.Assign(mNamespace);
+ jQName.Append(aDomainName);
+
+ // this char* has two homes, make sure it gets PL_free()ed properly
+ char* joinedQueueName = ToNewCString(jQName);
+ if (!joinedQueueName)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // link the observer to the joinedqueuename. home #1 for joinedQueueName
+ // these currently don't get removed until the destructor on this is called.
+ PL_HashTableAdd(mObservers, joinedQueueName, aObserver);
+
+ // store the domainName and JoinedQueueName, create a place to store the ID
+ tm_queue_mapping *qm = new tm_queue_mapping();
+ if (!qm)
+ return NS_ERROR_OUT_OF_MEMORY;
+ qm->queueID = TM_NO_ID; // initially no ID for the queue
+ qm->joinedQueueName = joinedQueueName; // home #2, owner of joinedQueueName
+ qm->domainName = ToNewCString(aDomainName);
+ if (!qm->domainName) {
+ PL_HashTableRemove(mObservers, joinedQueueName);
+ delete qm;
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ mQueueMaps.Append(qm);
+
+ nsresult rv = NS_ERROR_FAILURE;
+ tmTransaction trans;
+
+ // acquire a lock if neccessary
+ if (aLockingCall)
+ lockService->AcquireLock(joinedQueueName, PR_TRUE);
+ // XXX need to handle lock failures
+
+ if (NS_SUCCEEDED(trans.Init(0, // no IPC client
+ TM_NO_ID, // qID gets returned to us
+ TM_ATTACH, // action
+ NS_OK, // default status
+ (PRUint8 *)joinedQueueName, // qName gets copied
+ PL_strlen(joinedQueueName)+1))) { // message length
+ // send the attach msg
+ SendMessage(&trans, PR_TRUE); // synchronous
+ rv = NS_OK;
+ }
+
+ // drop the lock if neccessary
+ if (aLockingCall)
+ lockService->ReleaseLock(joinedQueueName);
+
+ return rv;
+}
+
+// actual removal of the observer takes place when we get the detach reply
+NS_IMETHODIMP
+tmTransactionService::Detach(const nsACString & aDomainName) {
+
+ // asynchronous detach
+ return SendDetachOrFlush(GetQueueID(aDomainName), TM_DETACH, PR_FALSE);
+
+}
+
+NS_IMETHODIMP
+tmTransactionService::Flush(const nsACString & aDomainName,
+ PRBool aLockingCall) {
+ // acquire a lock if neccessary
+ if (aLockingCall)
+ lockService->AcquireLock(GetJoinedQueueName(aDomainName), PR_TRUE);
+
+ // synchronous flush
+ nsresult rv = SendDetachOrFlush(GetQueueID(aDomainName), TM_FLUSH, PR_TRUE);
+
+ // drop the lock if neccessary
+ if (aLockingCall)
+ lockService->ReleaseLock(GetJoinedQueueName(aDomainName));
+
+ return rv;
+
+}
+
+NS_IMETHODIMP
+tmTransactionService::PostTransaction(const nsACString & aDomainName,
+ const PRUint8 *aData,
+ PRUint32 aDataLen) {
+
+ tmTransaction trans;
+ if (NS_SUCCEEDED(trans.Init(0, // no IPC client
+ GetQueueID(aDomainName), // qID returned to us
+ TM_POST, // action
+ NS_OK, // default status
+ aData, // message data
+ aDataLen))) { // message length
+ if (trans.GetQueueID() == TM_NO_ID) {
+ // stack it and pack it
+ tm_waiting_msg *msg = new tm_waiting_msg();
+ if (!msg)
+ return NS_ERROR_OUT_OF_MEMORY;
+ msg->trans = trans;
+ msg->domainName = ToNewCString(aDomainName);
+ if (!msg->domainName) {
+ delete msg;
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ mWaitingMessages.Append(msg);
+ }
+ else {
+ // send it
+ SendMessage(&trans, PR_FALSE);
+ }
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// ipcIMessageObserver
+
+NS_IMETHODIMP
+tmTransactionService::OnMessageAvailable(const PRUint32 aSenderID,
+ const nsID & aTarget,
+ const PRUint8 *aData,
+ PRUint32 aDataLength) {
+
+ nsresult rv = NS_ERROR_OUT_OF_MEMORY; // prime the return value
+
+ tmTransaction *trans = new tmTransaction();
+ if (trans) {
+ rv = trans->Init(0, // no IPC client ID
+ TM_INVALID_ID, // in aData
+ TM_INVALID_ID, // in aData
+ TM_INVALID_ID, // in aData
+ aData, // message data
+ aDataLength); // message length
+
+ if (NS_SUCCEEDED(rv)) {
+ switch(trans->GetAction()) {
+ case TM_ATTACH_REPLY:
+ OnAttachReply(trans);
+ break;
+ case TM_POST_REPLY:
+ // OnPostReply() would be called here
+ // isn't neccessary at the current time 2/19/03
+ break;
+ case TM_DETACH_REPLY:
+ OnDetachReply(trans);
+ break;
+ case TM_FLUSH_REPLY:
+ OnFlushReply(trans);
+ break;
+ case TM_POST:
+ OnPost(trans);
+ break;
+ default: // error, should not happen
+ NS_NOTREACHED("Recieved a TM reply outside of mapped messages");
+ break;
+ }
+ }
+ delete trans;
+ }
+ return rv;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Protected Member Functions
+
+void
+tmTransactionService::SendMessage(tmTransaction *aTrans, PRBool aSync) {
+
+ NS_ASSERTION(aTrans, "tmTransactionService::SendMessage called with null transaction");
+
+ IPC_SendMessage(0, kTransModuleID,
+ aTrans->GetRawMessage(),
+ aTrans->GetRawMessageLength());
+ if (aSync)
+ IPC_WaitMessage(0, kTransModuleID, nsnull, nsnull, PR_INTERVAL_NO_TIMEOUT);
+}
+
+void
+tmTransactionService::OnAttachReply(tmTransaction *aTrans) {
+
+ // if we attached, store the queue's ID
+ if (aTrans->GetStatus() >= 0) {
+
+ PRUint32 size = mQueueMaps.Size();
+ tm_queue_mapping *qmap = nsnull;
+ for (PRUint32 index = 0; index < size; index++) {
+ qmap = (tm_queue_mapping*) mQueueMaps[index];
+ if (qmap &&
+ PL_strcmp(qmap->joinedQueueName, (char*) aTrans->GetMessage()) == 0) {
+
+ // set the ID in the mapping
+ qmap->queueID = aTrans->GetQueueID();
+ // send any stored messges to the queue
+ DispatchStoredMessages(qmap);
+ }
+ }
+ }
+
+ // notify the observer we have attached (or didn't)
+ ipcITransactionObserver *observer =
+ (ipcITransactionObserver *)PL_HashTableLookup(mObservers,
+ (char*)aTrans->GetMessage());
+ if (observer)
+ observer->OnAttachReply(aTrans->GetQueueID(), aTrans->GetStatus());
+}
+
+void
+tmTransactionService::OnDetachReply(tmTransaction *aTrans) {
+
+ tm_queue_mapping *qmap = GetQueueMap(aTrans->GetQueueID());
+
+ // get the observer before we release the hashtable entry
+ ipcITransactionObserver *observer =
+ (ipcITransactionObserver *)PL_HashTableLookup(mObservers,
+ qmap->joinedQueueName);
+
+ // if it was removed, clean up
+ if (aTrans->GetStatus() >= 0) {
+
+ // remove the link between observer and queue
+ PL_HashTableRemove(mObservers, qmap->joinedQueueName);
+
+ // remove the mapping of queue names and id
+ mQueueMaps.Remove(qmap);
+ delete qmap;
+ }
+
+
+ // notify the observer -- could be didn't detach
+ if (observer)
+ observer->OnDetachReply(aTrans->GetQueueID(), aTrans->GetStatus());
+}
+
+void
+tmTransactionService::OnFlushReply(tmTransaction *aTrans) {
+
+ ipcITransactionObserver *observer =
+ (ipcITransactionObserver *)PL_HashTableLookup(mObservers,
+ GetJoinedQueueName(aTrans->GetQueueID()));
+ if (observer)
+ observer->OnFlushReply(aTrans->GetQueueID(), aTrans->GetStatus());
+}
+
+void
+tmTransactionService::OnPost(tmTransaction *aTrans) {
+
+ ipcITransactionObserver *observer =
+ (ipcITransactionObserver*) PL_HashTableLookup(mObservers,
+ GetJoinedQueueName(aTrans->GetQueueID()));
+ if (observer)
+ observer->OnTransactionAvailable(aTrans->GetQueueID(),
+ aTrans->GetMessage(),
+ aTrans->GetMessageLength());
+}
+
+void
+tmTransactionService::DispatchStoredMessages(tm_queue_mapping *aQMapping) {
+
+ PRUint32 size = mWaitingMessages.Size();
+ tm_waiting_msg *msg = nsnull;
+ for (PRUint32 index = 0; index < size; index ++) {
+ msg = (tm_waiting_msg*) mWaitingMessages[index];
+ // if the message is waiting on the queue passed in
+ if (msg && strcmp(aQMapping->domainName, msg->domainName) == 0) {
+
+ // found a match, send it and remove
+ msg->trans.SetQueueID(aQMapping->queueID);
+ SendMessage(&(msg->trans), PR_FALSE);
+
+ // clean up
+ mWaitingMessages.Remove(msg);
+ delete msg;
+ }
+ }
+}
+
+// searches against the short queue name
+PRInt32
+tmTransactionService::GetQueueID(const nsACString & aDomainName) {
+
+ PRUint32 size = mQueueMaps.Size();
+ tm_queue_mapping *qmap = nsnull;
+ for (PRUint32 index = 0; index < size; index++) {
+ qmap = (tm_queue_mapping*) mQueueMaps[index];
+ if (qmap && aDomainName.Equals(qmap->domainName))
+ return qmap->queueID;
+ }
+ return TM_NO_ID;
+}
+
+char*
+tmTransactionService::GetJoinedQueueName(PRUint32 aQueueID) {
+
+ PRUint32 size = mQueueMaps.Size();
+ tm_queue_mapping *qmap = nsnull;
+ for (PRUint32 index = 0; index < size; index++) {
+ qmap = (tm_queue_mapping*) mQueueMaps[index];
+ if (qmap && qmap->queueID == aQueueID)
+ return qmap->joinedQueueName;
+ }
+ return nsnull;
+}
+
+char*
+tmTransactionService::GetJoinedQueueName(const nsACString & aDomainName) {
+
+ PRUint32 size = mQueueMaps.Size();
+ tm_queue_mapping *qmap = nsnull;
+ for (PRUint32 index = 0; index < size; index++) {
+ qmap = (tm_queue_mapping*) mQueueMaps[index];
+ if (qmap && aDomainName.Equals(qmap->domainName))
+ return qmap->joinedQueueName;
+ }
+ return nsnull;
+}
+
+tm_queue_mapping*
+tmTransactionService::GetQueueMap(PRUint32 aQueueID) {
+
+ PRUint32 size = mQueueMaps.Size();
+ tm_queue_mapping *qmap = nsnull;
+ for (PRUint32 index = 0; index < size; index++) {
+ qmap = (tm_queue_mapping*) mQueueMaps[index];
+ if (qmap && qmap->queueID == aQueueID)
+ return qmap;
+ }
+ return nsnull;
+}
+
+nsresult
+tmTransactionService::SendDetachOrFlush(PRUint32 aQueueID,
+ PRUint32 aAction,
+ PRBool aSync) {
+
+ // if the queue isn't attached to, just return
+ if (aQueueID == TM_NO_ID)
+ return NS_ERROR_UNEXPECTED;
+
+ tmTransaction trans;
+ if (NS_SUCCEEDED(trans.Init(0, // no IPC client
+ aQueueID, // qID to detach from
+ aAction, // action
+ NS_OK, // default status
+ nsnull, // no message
+ 0))) { // no message
+ // send it
+ SendMessage(&trans, aSync);
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h
new file mode 100644
index 00000000..cd9310fe
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h
@@ -0,0 +1,196 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _tmTransactionService_H_
+#define _tmTransactionService_H_
+
+#include "ipcdclient.h"
+#include "ipcILockService.h"
+#include "ipcIMessageObserver.h"
+#include "ipcITransactionService.h"
+#include "nsString.h"
+#include "nsVoidArray.h"
+#include "plhash.h"
+#include "tmTransaction.h"
+#include "tmVector.h"
+
+struct tm_queue_mapping;
+
+/**
+ * The tmTransactionService shares packets of information
+ * (transactions) with other Gecko based applications interested in the same
+ * namespace and domain. An application registers with the Transaction Service
+ * for a particular namespace and domain and then can post transactions to the
+ * service and receive transactions from the service.
+ *
+ * For applications using the Transaction Service to share changes in state that
+ * get reflected in files on disk there are certain pattersn to follow to ensure
+ * data loss does not occur.
+ *
+ * Startup: XXX docs needed
+ *
+ * Shutdown/writing to disk: XXX docs needed
+ *
+ *
+ */
+class tmTransactionService : public ipcITransactionService,
+ public ipcIMessageObserver
+{
+
+public:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Constructor & Destructor
+ tmTransactionService() : mObservers(0) {};
+
+ /**
+ * Reclaim all the memory allocated: PL_hashtable, tmVectors
+ */
+ virtual ~tmTransactionService();
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Interface Declarations
+
+ // for API docs, see the respective *.idl files
+ NS_DECL_ISUPPORTS
+ NS_DECL_IPCITRANSACTIONSERVICE
+ NS_DECL_IPCIMESSAGEOBSERVER
+
+protected:
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Protected Member Functions
+
+ /**
+ * Pulls the raw message out of the transaction and sends it to the IPC
+ * service to be delivered to the TM.
+ *
+ * @param aTrans
+ * The transaction to send to the TM
+ *
+ * @param aSync
+ * If TRUE, calling thread will be blocked until a reply is
+ * received.
+ */
+ void SendMessage(tmTransaction *aTrans, PRBool aSync);
+
+ // handlers for reply messages from TransactionManager
+
+ /**
+ * Pulls the queueID out of the ATTACH_REPLY message and stores it in the
+ * proper tm_queue_mapping object. Calls DispatchStoredMessages() to make
+ * sure we send any messages that have been waiting on the ATTACH_REPLY.
+ * Also calls the OnAttachReply() method for the observer of the queue.
+ */
+ void OnAttachReply(tmTransaction *aTrans);
+
+ /**
+ * Removes the tm_queue_mapping object and calls the OnDetachReply() method
+ * on the observer of the queue detached.
+ */
+ void OnDetachReply(tmTransaction *aTrans);
+
+ /**
+ * Calls the OnFlushReply method of the observer of the queue.
+ */
+ void OnFlushReply(tmTransaction *aTrans);
+
+ /**
+ * Calls the OnPost method of the observer of the queue.
+ */
+ void OnPost(tmTransaction *aTrans);
+
+ // other helper functions
+
+ /**
+ * Cycle through the collection of transactions waiting to go out and
+ * send any that are waiting on an ATTACH_REPLY from the queue
+ * specified by the tm_queue_mapping passed in.
+ */
+ void DispatchStoredMessages(tm_queue_mapping *aQMapping);
+
+ // helper methods for accessing the void arrays
+
+ /**
+ * @returns the ID corresponding to the domain name passed in
+ * @returns TM_NO_ID if the name is not found.
+ */
+ PRInt32 GetQueueID(const nsACString & aDomainName);
+
+ /**
+ * @returns the joined queue name - namespace + domain
+ * (prefs, cookies etc) corresponding to the ID passed in.
+ * @returns nsnull if the ID is not found.
+ */
+ char* GetJoinedQueueName(PRUint32 aQueueID);
+
+ /**
+ * @returns the joined queue name - namespace + domain
+ * (prefs, cookies etc) corresponding to the ID passed in.
+ * @returns nsnull if the ID is not found.
+ */
+ char* GetJoinedQueueName(const nsACString & aDomainName);
+
+ /**
+ * @returns the tm_queue_mapping object that contains the ID passed in.
+ * @returns nsnull if the ID is not found.
+ */
+ tm_queue_mapping* GetQueueMap(PRUint32 aQueueID);
+
+ /**
+ * Helper method for Detach and Flush requests.
+ */
+ nsresult SendDetachOrFlush(PRUint32 aQueueID,
+ PRUint32 aAction,
+ PRBool aSync);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Protected Member Variables
+
+ nsCString mNamespace; // limit domains to the namespace
+ PLHashTable *mObservers; // maps qName -> ipcITransactionObserver
+
+ tmVector mQueueMaps; // queue - name - domain mappings
+ tmVector mWaitingMessages; // messages sent before ATTACH_REPLY
+
+ nsCOMPtr<ipcILockService> lockService; // cache the lock service
+
+private:
+
+};
+
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/.cvsignore
new file mode 100644
index 00000000..e3c610be
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+tmModuleTest.exe
+tmModuleTest.ilk
+tmModuleTest.pdb
+tmModuleTest.obj
+tmModuleTest
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/Makefile.in
new file mode 100644
index 00000000..385751a3
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/Makefile.in
@@ -0,0 +1,68 @@
+# ***** 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 Transaction Manager.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corp.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# John Gaunt <jgaunt@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = tm_test
+
+REQUIRES = ipcd \
+ nspr \
+ string \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = \
+ tmModuleTest.cpp \
+ $(NULL)
+
+SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
+
+include $(topsrcdir)/config/config.mk
+
+LIBS = \
+ $(EXTRA_DSO_LIBS) \
+ $(XPCOM_LIBS) \
+ $(NSPR_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/tmModuleTest.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/tmModuleTest.cpp
new file mode 100644
index 00000000..5d1dccd4
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/tmModuleTest.cpp
@@ -0,0 +1,323 @@
+/* ***** 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 Transaction Manager.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corp.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gaunt <jgaunt@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// transaction manager includes
+#include "ipcITransactionService.h"
+#include "ipcITransactionObserver.h"
+
+// ipc daemon includes
+#include "ipcIService.h"
+
+// core & xpcom ns includes
+#include "nsDebug.h"
+#include "nsIEventQueueService.h"
+#include "nsIServiceManager.h"
+#include "nsIComponentRegistrar.h"
+#include "nsString.h"
+
+// nspr includes
+#include "prmem.h"
+#include "plgetopt.h"
+#include "nspr.h"
+#include "prlog.h"
+
+//////////////////////////////////////////////////////////////////////////////
+// Testing/Debug/Logging BEGIN
+
+const int NameSize = 1024;
+
+/* command line options */
+PRIntn optDebug = 0;
+char optMode = 's';
+char *profileName = new char[NameSize];
+char *queueName = new char[NameSize];
+
+char *data = new char[NameSize];
+PRUint32 dataLen = 10; // includes the null terminator for "test data"
+
+// Testing/Debug/Logging END
+//////////////////////////////////////////////////////////////////////////////
+
+#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;
+static ipcIService *gIpcServ = nsnull;
+static ipcITransactionService *gTransServ = nsnull;
+
+//-----------------------------------------------------------------------------
+
+class myTransactionObserver : public ipcITransactionObserver
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_IPCITRANSACTIONOBSERVER
+
+ myTransactionObserver() { }
+};
+
+NS_IMPL_ISUPPORTS1(myTransactionObserver, ipcITransactionObserver)
+
+NS_IMETHODIMP myTransactionObserver::OnTransactionAvailable(PRUint32 aQueueID, const PRUint8 *aData, PRUint32 aDataLen)
+{
+ printf("tmModuleTest: myTransactionObserver::OnTransactionAvailable [%s]\n", aData);
+ return NS_OK;
+}
+
+NS_IMETHODIMP myTransactionObserver::OnAttachReply(PRUint32 aQueueID, PRUint32 aStatus)
+{
+ printf("tmModuleTest: myTransactionObserver::OnAttachReply [%d]\n", aStatus);
+ return NS_OK;
+}
+
+NS_IMETHODIMP myTransactionObserver::OnDetachReply(PRUint32 aQueueID, PRUint32 aStatus)
+{
+ printf("tmModuleTest: myTransactionObserver::OnDetachReply [%d]\n", aStatus);
+ return NS_OK;
+}
+
+NS_IMETHODIMP myTransactionObserver::OnFlushReply(PRUint32 aQueueID, PRUint32 aStatus)
+{
+ printf("tmModuleTest: myTransactionObserver::OnFlushReply [%d]\n", aStatus);
+ return NS_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+
+int main(PRInt32 argc, char *argv[])
+{
+ nsresult rv;
+
+ // default string values
+ strcpy(profileName, "defaultProfile");
+ strcpy(queueName, "defaultQueue");
+ strcpy(data, "test data");
+
+ { // scope the command line option gathering (needed for some reason)
+
+ // Get command line options
+ PLOptStatus os;
+ PLOptState *opt = PL_CreateOptState(argc, argv, "bdfhlp:q:");
+
+ while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+ {
+ if (PL_OPT_BAD == os) continue;
+ switch (opt->option)
+ {
+ case 'b': /* broadcast a bunch of messages */
+ printf("tmModuleTest: broadcaster\n");
+ optMode = 'b';
+ break;
+ case 'd': /* debug mode */
+ printf("tmModuleTest: debugging baby\n");
+ optDebug = 1;
+ break;
+ case 'f': /* broadcast and flush */
+ printf("tmModuleTest: flusher\n");
+ optMode = 'f';
+ break;
+ case 'h': /* broadcast and detach */
+ printf("tmModuleTest: hit-n-run\n");
+ optMode = 'h';
+ break;
+ case 'l': /* don't broadcast, just listen */
+ printf("tmModuleTest: listener\n");
+ optMode = 'l';
+ break;
+ case 'p': /* set the profile name */
+ strcpy(profileName, opt->value);
+ printf("tmModuleTest: profilename:%s\n",profileName);
+ break;
+ case 'q': /* set the queue name */
+ strcpy(queueName, opt->value);
+ printf("tmModuleTest: queuename:%s\n",queueName);
+ break;
+ default:
+ printf("tmModuleTest: default\n");
+ break;
+ }
+ }
+ PL_DestroyOptState(opt);
+ } // scope the command line option gathering (needed for some reason)
+
+ { // scope the nsCOMPtrs
+
+ printf("tmModuleTest: Starting xpcom\n");
+
+ // xpcom startup stuff
+ nsCOMPtr<nsIServiceManager> servMan;
+ NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull);
+ nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
+ NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
+ if (registrar)
+ registrar->AutoRegister(nsnull);
+
+ // Create the Event Queue for this thread...
+ nsCOMPtr<nsIEventQueueService> 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");
+
+ // Need to make sure the ipc system has been started
+ printf("tmModuleTest: getting ipc service\n");
+ nsCOMPtr<ipcIService> ipcServ(do_GetService("@mozilla.org/ipc/service;1", &rv));
+ RETURN_IF_FAILED(rv, "do_GetService(ipcServ)");
+ NS_ADDREF(gIpcServ = ipcServ);
+
+ // Get the transaction service
+ printf("tmModuleTest: getting transaction service\n");
+ nsCOMPtr<ipcITransactionService> transServ(do_GetService("@mozilla.org/ipc/transaction-service;1", &rv));
+ RETURN_IF_FAILED(rv, "do_GetService(transServ)");
+ NS_ADDREF(gTransServ = transServ);
+
+ // transaction specifc startup stuff, done for all cases
+
+ nsCOMPtr<ipcITransactionObserver> observ = new myTransactionObserver();
+
+ // initialize the transaction service with a specific profile
+ gTransServ->Init(nsDependentCString(profileName));
+ printf("tmModuleTest: using profileName [%s]\n", profileName);
+
+ // attach to the queue in the transaction manager
+ gTransServ->Attach(nsDependentCString(queueName), observ, PR_TRUE);
+ printf("tmModuleTest: observing queue [%s]\n", queueName);
+
+
+ // run specific patterns based on the mode
+ int i = 0; // wasn't working inside the cases
+ switch (optMode)
+ {
+ case 's':
+ printf("tmModuleTest: start standard\n");
+ // post a couple events
+ for (; i < 5 ; i++) {
+ gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen);
+ }
+ // listen for events
+ while (gKeepRunning)
+ gEventQ->ProcessPendingEvents();
+ printf("tmModuleTest: end standard\n");
+ break;
+ case 'b':
+ printf("tmModuleTest: start broadcast\n");
+ // post a BUNCH of messages
+ for (; i < 50; i++) {
+ gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen);
+ }
+ // listen for events
+ while (gKeepRunning)
+ gEventQ->ProcessPendingEvents();
+ printf("tmModuleTest: end broadcast\n");
+ break;
+ case 'f':
+ printf("tmModuleTest: start flush\n");
+ // post a couple events
+ for (; i < 5; i++) {
+ gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen);
+ }
+ // flush the queue
+ gTransServ->Flush(nsDependentCString(queueName), PR_TRUE);
+ // post a couple events
+ for (i=0; i < 8; i++) {
+ gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen);
+ }
+ // listen for events
+ while (gKeepRunning)
+ gEventQ->ProcessPendingEvents();
+ // detach
+ gTransServ->Detach(nsDependentCString(queueName));
+ printf("tmModuleTest: end flush\n");
+ break;
+ case 'h':
+ printf("tmModuleTest: start hit-n-run\n");
+ // post a couple events
+ for (; i < 5; i++) {
+ gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen);
+ }
+ // detach
+ gTransServ->Detach(nsDependentCString(queueName));
+ printf("tmModuleTest: end hit-n-run\n");
+ break;
+ case 'l':
+ printf("tmModuleTest: start listener\n");
+ // listen for events
+ while (gKeepRunning)
+ gEventQ->ProcessPendingEvents();
+ printf("tmModuleTest: end listener\n");
+ break;
+ default :
+ printf("tmModuleTest: start & end default\n");
+ break;
+ }
+
+ // shutdown process
+
+ NS_RELEASE(gTransServ);
+ NS_RELEASE(gIpcServ);
+
+ printf("tmModuleTest: processing remaining events\n");
+
+ // process any remaining events
+ PLEvent *ev;
+ while (NS_SUCCEEDED(gEventQ->GetEvent(&ev)) && ev)
+ gEventQ->HandleEvent(ev);
+
+ printf("tmModuleTest: done\n");
+ } // this scopes the nsCOMPtrs
+
+ // helps with shutdown on some cases
+ PR_Sleep(PR_SecondsToInterval(4));
+
+ // 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/src/libs/xpcom18a4/ipc/ipcd/ipc.pkg b/src/libs/xpcom18a4/ipc/ipcd/ipc.pkg
new file mode 100644
index 00000000..a2171122
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/ipc.pkg
@@ -0,0 +1,21 @@
+[gecko]
+dist/bin/mozipcd@BINS@
+#if OS_ARCH==OS2
+dist/bin/ipc/modules/@DLLP@lockmod@DLLS@
+#else
+dist/bin/ipc/modules/@DLLP@lockmodule@DLLS@
+#endif
+dist/bin/ipc/modules/@DLLP@transmgr@DLLS@
+dist/bin/components/@DLLP@ipcdc@DLLS@
+!xpt dist/bin/components/ipcd.xpt
+
+#if ENABLE_TESTS
+[gecko-tests]
+dist/bin/TestIPC@BINS@
+dist/bin/tmModuleTest@BINS@
+#if USE_SHORT_LIBNAME
+dist/bin/ipc/modules/@DLLP@testmod@DLLS@
+#else
+dist/bin/ipc/modules/@DLLP@testmodule@DLLS@
+#endif
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in
new file mode 100644
index 00000000..ffcaa10c
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in
@@ -0,0 +1,65 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+LIBRARY_NAME = ipcdshared_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME = ipcd
+
+# required for #include "nsID.h"
+REQUIRES = \
+ xpcom \
+ $(NULL)
+
+CPPSRCS = \
+ ipcLog.cpp \
+ ipcConfig.cpp \
+ ipcMessage.cpp \
+ ipcMessagePrimitives.cpp \
+ ipcStringList.cpp \
+ ipcIDList.cpp \
+ ipcm.cpp
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp
new file mode 100644
index 00000000..5f829626
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp
@@ -0,0 +1,104 @@
+/* ***** 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) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if defined(XP_WIN)
+#elif defined(XP_OS2) && defined(XP_OS2_NATIVEIPC)
+#else
+#include <string.h>
+#ifdef XP_UNIX
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#endif
+#include "ipcConfig.h"
+#include "ipcLog.h"
+#include "prenv.h"
+#include "plstr.h"
+
+#if defined(XP_OS2) && !defined(XP_OS2_NATIVEIPC)
+#ifdef VBOX
+static const char kDefaultSocketPrefix[] = "\\socket\\vbox-";
+#else
+static const char kDefaultSocketPrefix[] = "\\socket\\mozilla-";
+#endif
+static const char kDefaultSocketSuffix[] = "-ipc\\ipcd";
+#else
+#ifdef VBOX
+static const char kDefaultSocketPrefix[] = "/tmp/.vbox-";
+#else
+static const char kDefaultSocketPrefix[] = "/tmp/.mozilla-";
+#endif
+static const char kDefaultSocketSuffix[] = "-ipc/ipcd";
+#endif
+
+void IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen)
+{
+ const char *logName;
+ int len;
+
+ PL_strncpyz(buf, kDefaultSocketPrefix, bufLen);
+ buf += (sizeof(kDefaultSocketPrefix) - 1);
+ bufLen -= (sizeof(kDefaultSocketPrefix) - 1);
+
+ logName = PR_GetEnv("VBOX_IPC_SOCKETID");
+#if defined(VBOX) && defined(XP_UNIX)
+ if (!logName || !logName[0]) {
+ struct passwd *passStruct = getpwuid(getuid());
+ if (passStruct)
+ logName = passStruct->pw_name;
+ }
+#endif
+ if (!logName || !logName[0]) {
+ logName = PR_GetEnv("LOGNAME");
+ if (!logName || !logName[0]) {
+ logName = PR_GetEnv("USER");
+ if (!logName || !logName[0]) {
+ LOG(("could not determine username from environment\n"));
+ goto end;
+ }
+ }
+ }
+ PL_strncpyz(buf, logName, bufLen);
+ len = strlen(logName);
+ buf += len;
+ bufLen -= len;
+
+end:
+ PL_strncpyz(buf, kDefaultSocketSuffix, bufLen);
+}
+
+#endif
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h
new file mode 100644
index 00000000..ab8b10e5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h
@@ -0,0 +1,98 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcProto_h__
+#define ipcProto_h__
+
+#if defined(XP_WIN)
+//
+// use WM_COPYDATA messages
+//
+#include "prprf.h"
+
+#define IPC_WINDOW_CLASS "Mozilla:IPCWindowClass"
+#define IPC_WINDOW_NAME "Mozilla:IPCWindow"
+#define IPC_CLIENT_WINDOW_CLASS "Mozilla:IPCAppWindowClass"
+#define IPC_CLIENT_WINDOW_NAME_PREFIX "Mozilla:IPCAppWindow:"
+#define IPC_SYNC_EVENT_NAME "Local\\MozillaIPCSyncEvent"
+#ifndef IPC_DAEMON_APP_NAME
+#define IPC_DAEMON_APP_NAME "mozilla-ipcd.exe"
+#endif
+#define IPC_PATH_SEP_CHAR '\\'
+#define IPC_MODULES_DIR "ipc\\modules"
+
+#define IPC_CLIENT_WINDOW_NAME_MAXLEN (sizeof(IPC_CLIENT_WINDOW_NAME_PREFIX) + 20)
+
+// writes client name into buf. buf must be at least
+// IPC_CLIENT_WINDOW_NAME_MAXLEN bytes in length.
+inline void IPC_GetClientWindowName(PRUint32 pid, char *buf)
+{
+ PR_snprintf(buf, IPC_CLIENT_WINDOW_NAME_MAXLEN, "%s%u",
+ IPC_CLIENT_WINDOW_NAME_PREFIX, pid);
+}
+
+#else
+#include "nscore.h"
+//
+// use UNIX domain socket
+//
+#define IPC_PORT 0
+#define IPC_SOCKET_TYPE "ipc"
+#if defined(XP_OS2)
+#ifndef IPC_DAEMON_APP_NAME
+#define IPC_DAEMON_APP_NAME "mozilla-ipcd.exe"
+#endif
+#define IPC_PATH_SEP_CHAR '\\'
+#define IPC_MODULES_DIR "ipc\\modules"
+#else
+#ifndef IPC_DAEMON_APP_NAME
+#define IPC_DAEMON_APP_NAME "mozilla-ipcd"
+#endif
+#define IPC_PATH_SEP_CHAR '/'
+#define IPC_MODULES_DIR "ipc/modules"
+#endif
+
+NS_HIDDEN_(void) IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen);
+
+#endif
+
+// common shared configuration values
+
+#define IPC_STARTUP_PIPE_NAME "ipc:startup-pipe"
+#define IPC_STARTUP_PIPE_MAGIC 0x1C
+
+#endif // !ipcProto_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp
new file mode 100644
index 00000000..0f64a3a0
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp
@@ -0,0 +1,62 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcIDList.h"
+
+ipcIDNode *
+ipcIDList::FindNode(ipcIDNode *node, const nsID &id)
+{
+ while (node) {
+ if (node->Equals(id))
+ return node;
+ node = node->mNext;
+ }
+ return NULL;
+}
+
+ipcIDNode *
+ipcIDList::FindNodeBefore(ipcIDNode *node, const nsID &id)
+{
+ ipcIDNode *prev = NULL;
+ while (node) {
+ if (node->Equals(id))
+ return prev;
+ prev = node;
+ node = node->mNext;
+ }
+ return NULL;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h
new file mode 100644
index 00000000..b4fd1512
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h
@@ -0,0 +1,108 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcIDList_h__
+#define ipcIDList_h__
+
+#include "nsID.h"
+#include "ipcList.h"
+
+//-----------------------------------------------------------------------------
+// nsID node
+//-----------------------------------------------------------------------------
+
+class ipcIDNode
+{
+public:
+ ipcIDNode(const nsID &id)
+ : mID(id)
+ { }
+
+ const nsID &Value() const { return mID; }
+
+ PRBool Equals(const nsID &id) const { return mID.Equals(id); }
+
+ class ipcIDNode *mNext;
+private:
+ nsID mID;
+};
+
+//-----------------------------------------------------------------------------
+// singly-linked list of nsIDs
+//-----------------------------------------------------------------------------
+
+class ipcIDList : public ipcList<ipcIDNode>
+{
+public:
+ typedef ipcList<ipcIDNode> Super;
+
+ void Prepend(const nsID &id)
+ {
+ Super::Prepend(new ipcIDNode(id));
+ }
+
+ void Append(const nsID &id)
+ {
+ Super::Append(new ipcIDNode(id));
+ }
+
+ const ipcIDNode *Find(const nsID &id) const
+ {
+ return FindNode(mHead, id);
+ }
+
+ PRBool FindAndDelete(const nsID &id)
+ {
+ ipcIDNode *node = FindNodeBefore(mHead, id);
+ if (node) {
+ DeleteAfter(node);
+ return PR_TRUE;
+ }
+ else if (!IsEmpty()) {
+ DeleteFirst();
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+ }
+
+private:
+ static NS_HIDDEN_(ipcIDNode *) FindNode (ipcIDNode *head, const nsID &id);
+ static NS_HIDDEN_(ipcIDNode *) FindNodeBefore(ipcIDNode *head, const nsID &id);
+};
+
+#endif // !ipcIDList_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h
new file mode 100644
index 00000000..a9b9c959
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h
@@ -0,0 +1,211 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcList_h__
+#define ipcList_h__
+
+#include "prtypes.h"
+
+//-----------------------------------------------------------------------------
+// simple list of singly-linked objects. class T must have the following
+// structure:
+//
+// class T {
+// ...
+// public:
+// T *mNext;
+// };
+//
+// objects added to the list must be allocated with operator new. class T may
+// optionally inherit from ipcListNode<T> if it doesn't wish to define mNext
+// explicitly.
+//-----------------------------------------------------------------------------
+
+template<class T>
+class ipcList
+{
+public:
+ ipcList()
+ : mHead(NULL)
+ , mTail(NULL)
+ { }
+ ~ipcList() { DeleteAll(); }
+
+ //
+ // prepends obj at the beginning of the list.
+ //
+ void Prepend(T *obj)
+ {
+ obj->mNext = mHead;
+ mHead = obj;
+ if (!mTail)
+ mTail = mHead;
+ }
+
+ //
+ // appends obj to the end of the list.
+ //
+ void Append(T *obj)
+ {
+ obj->mNext = NULL;
+ if (mTail) {
+ mTail->mNext = obj;
+ mTail = obj;
+ }
+ else
+ mTail = mHead = obj;
+ }
+
+ //
+ // inserts b into the list after a.
+ //
+ void InsertAfter(T *a, T *b)
+ {
+ b->mNext = a->mNext;
+ a->mNext = b;
+ if (mTail == a)
+ mTail = b;
+ }
+
+ //
+ // removes first element w/o deleting it
+ //
+ void RemoveFirst()
+ {
+ if (mHead)
+ AdvanceHead();
+ }
+
+ //
+ // removes element after the given element w/o deleting it
+ //
+ void RemoveAfter(T *obj)
+ {
+ T *rej = obj->mNext;
+ if (rej) {
+ obj->mNext = rej->mNext;
+ if (rej == mTail)
+ mTail = obj;
+ }
+ }
+
+ //
+ // deletes first element
+ //
+ void DeleteFirst()
+ {
+ T *first = mHead;
+ if (first) {
+ AdvanceHead();
+ delete first;
+ }
+ }
+
+ //
+ // deletes element after the given element
+ //
+ void DeleteAfter(T *obj)
+ {
+ T *rej = obj->mNext;
+ if (rej) {
+ RemoveAfter(obj);
+ delete rej;
+ }
+ }
+
+ //
+ // deletes all elements
+ //
+ void DeleteAll()
+ {
+ while (mHead)
+ DeleteFirst();
+ }
+
+ const T *First() const { return mHead; }
+ T *First() { return mHead; }
+ const T *Last() const { return mTail; }
+ T *Last() { return mTail; }
+
+ PRBool IsEmpty() const { return mHead == NULL; }
+
+ //
+ // moves contents of list to another list
+ //
+ void MoveTo(ipcList<T> &other)
+ {
+ other.mHead = mHead;
+ other.mTail = mTail;
+ mHead = NULL;
+ mTail = NULL;
+ }
+
+ // gets count of list elements
+ PRUint32 Count()
+ {
+ T *obj = mHead;
+ PRUint32 count = 0;
+ while (obj) {
+ count++;
+ obj = obj->mNext;
+ }
+
+ return count;
+ }
+
+protected:
+ void AdvanceHead()
+ {
+ mHead = mHead->mNext;
+ if (!mHead)
+ mTail = NULL;
+ }
+
+ T *mHead;
+ T *mTail;
+};
+
+template<class T>
+class ipcListNode
+{
+public:
+ ipcListNode() : mNext(nsnull) {}
+
+ T *mNext;
+};
+
+#endif // !ipcList_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp
new file mode 100644
index 00000000..340b211c
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp
@@ -0,0 +1,181 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcLog.h"
+
+#ifdef IPC_LOGGING
+
+#include <string.h>
+#include <ctype.h>
+
+#include "prenv.h"
+#include "prprf.h"
+#include "prthread.h"
+#include "plstr.h"
+
+#ifdef VBOX
+# if defined(__OS2__) && defined(PAGE_SIZE)
+# undef PAGE_SIZE
+# endif
+# include <iprt/initterm.h> // for RTR3InitDll
+#else // !VBOX
+PRBool ipcLogEnabled = PR_FALSE;
+#endif // !VBOX
+
+char ipcLogPrefix[10] = {0};
+
+#ifndef VBOX
+
+//-----------------------------------------------------------------------------
+// UNIX
+//-----------------------------------------------------------------------------
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+
+#include <sys/types.h>
+#include <unistd.h>
+
+static inline PRUint32
+WritePrefix(char *buf, PRUint32 bufLen)
+{
+ return PR_snprintf(buf, bufLen, "[%u:%p] %s ",
+ (unsigned) getpid(),
+ PR_GetCurrentThread(),
+ ipcLogPrefix);
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// WIN32
+//-----------------------------------------------------------------------------
+#ifdef XP_WIN
+#include <windows.h>
+
+static inline PRUint32
+WritePrefix(char *buf, PRUint32 bufLen)
+{
+ return PR_snprintf(buf, bufLen, "[%u:%p] %s ",
+ GetCurrentProcessId(),
+ PR_GetCurrentThread(),
+ ipcLogPrefix);
+}
+#endif
+
+#endif // !VBOX
+
+//-----------------------------------------------------------------------------
+// logging API impl
+//-----------------------------------------------------------------------------
+
+void
+IPC_InitLog(const char *prefix)
+{
+#ifdef VBOX
+ // initialize VBox Runtime
+ RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
+
+ PL_strncpyz(ipcLogPrefix, prefix, sizeof(ipcLogPrefix));
+#else
+ if (PR_GetEnv("IPC_LOG_ENABLE")) {
+ ipcLogEnabled = PR_TRUE;
+ PL_strncpyz(ipcLogPrefix, prefix, sizeof(ipcLogPrefix));
+ }
+#endif
+}
+
+void
+IPC_Log(const char *fmt, ... )
+{
+ va_list ap;
+ va_start(ap, fmt);
+ PRUint32 nb = 0;
+ char buf[512];
+
+#ifdef VBOX
+ if (ipcLogPrefix[0]) {
+ nb = strlen(ipcLogPrefix);
+ if (nb > sizeof(buf) - 2)
+ nb = sizeof(buf) - 2;
+ PL_strncpy(buf, ipcLogPrefix, nb);
+ buf[nb++] = ' ';
+ }
+#else
+ if (ipcLogPrefix[0])
+ nb = WritePrefix(buf, sizeof(buf));
+#endif
+
+ PR_vsnprintf(buf + nb, sizeof(buf) - nb, fmt, ap);
+ buf[sizeof(buf) - 1] = '\0';
+
+#ifdef VBOX
+ LogFlow(("%s", buf));
+#else
+ fwrite(buf, strlen(buf), 1, stdout);
+#endif
+
+ va_end(ap);
+}
+
+void
+IPC_LogBinary(const PRUint8 *data, PRUint32 len)
+{
+ PRUint32 i, j, ln;
+ for (i=0; i<len; ) {
+ char line[100] = "";
+ const PRUint8 *p;
+
+ ln = 0;
+
+ p = &data[i];
+ for (j=0; j<PR_MIN(8, len - i); ++j, ++p)
+ ln += PR_snprintf(line + ln, sizeof(line) - ln, "%02x ", *p);
+
+ for (; ln < 32; ++ln)
+ line[ln] = ' ';
+
+ p = &data[i];
+ for (j=0; j<PR_MIN(8, len - i); ++j, ++p)
+ ln += PR_snprintf(line + ln, sizeof(line) - ln, "%c", isprint(*p) ? *p : '.');
+
+ line[ln] = '\0';
+
+ i += (p - &data[i]);
+
+ LOG(("%s\n", line));
+ }
+}
+
+#endif // IPC_LOGGING
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.h
new file mode 100644
index 00000000..e21f6211
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.h
@@ -0,0 +1,111 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcLog_h__
+#define ipcLog_h__
+
+#include "nscore.h"
+#include "prtypes.h"
+
+#ifndef VBOX
+#ifdef DEBUG
+#define IPC_LOGGING
+#endif
+#endif
+
+#ifdef IPC_LOGGING
+
+#ifdef VBOX
+
+/* Redefine logging group to IPC */
+# ifdef LOG_GROUP
+# undef LOG_GROUP
+# endif
+# define LOG_GROUP LOG_GROUP_IPC
+
+/* Ensure log macros are enabled */
+# ifndef LOG_ENABLED
+# define LOG_ENABLED
+# endif
+
+#include <VBox/log.h>
+
+extern NS_HIDDEN_(void) IPC_InitLog(const char *prefix);
+extern NS_HIDDEN_(void) IPC_Log(const char *fmt, ...);
+extern NS_HIDDEN_(void) IPC_LogBinary(const PRUint8 *data, PRUint32 len);
+
+# define IPC_LOG(_args) \
+ PR_BEGIN_MACRO \
+ if (IPC_LOG_ENABLED()) \
+ IPC_Log _args; \
+ PR_END_MACRO
+
+/* IPC_Log() internally uses LogFlow() so use LogIsFlowEnabled() below */
+# define IPC_LOG_ENABLED() (LogIsFlowEnabled())
+
+# define LOG(args) IPC_LOG(args)
+
+#else /* !VBOX */
+
+extern PRBool ipcLogEnabled;
+extern NS_HIDDEN_(void) IPC_InitLog(const char *prefix);
+extern NS_HIDDEN_(void) IPC_Log(const char *fmt, ...);
+extern NS_HIDDEN_(void) IPC_LogBinary(const PRUint8 *data, PRUint32 len);
+
+#define IPC_LOG(_args) \
+ PR_BEGIN_MACRO \
+ if (ipcLogEnabled) \
+ IPC_Log _args; \
+ PR_END_MACRO
+
+#define IPC_LOG_ENABLED() ipcLogEnabled
+
+#define LOG(args) IPC_LOG(args)
+
+#endif /* !VBOX */
+
+#else // IPC_LOGGING
+
+#define IPC_InitLog(prefix) PR_BEGIN_MACRO PR_END_MACRO
+#define IPC_LogBinary(data, len) PR_BEGIN_MACRO PR_END_MACRO
+#define IPC_LOG(_args) PR_BEGIN_MACRO PR_END_MACRO
+#define IPC_LOG_ENABLED() (0)
+#define LOG(args) PR_BEGIN_MACRO PR_END_MACRO
+
+#endif // IPC_LOGGING
+
+#endif // !ipcLog_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp
new file mode 100644
index 00000000..bfdc7efe
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp
@@ -0,0 +1,280 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <stdlib.h>
+#include <string.h>
+#include "prlog.h"
+#include "ipcMessage.h"
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+# include <iprt/mem.h>
+#endif
+
+ipcMessage::~ipcMessage()
+{
+ if (mMsgHdr)
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ RTMemFree(mMsgHdr);
+#else
+ free(mMsgHdr);
+#endif
+}
+
+void
+ipcMessage::Reset()
+{
+ if (mMsgHdr) {
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ RTMemFree(mMsgHdr);
+#else
+ free(mMsgHdr);
+#endif
+ mMsgHdr = NULL;
+ }
+
+ mMsgOffset = 0;
+ mMsgComplete = PR_FALSE;
+}
+
+ipcMessage *
+ipcMessage::Clone() const
+{
+ ipcMessage *clone = new ipcMessage();
+ if (!clone)
+ return NULL;
+
+ // copy buf if non-null
+ if (mMsgHdr) {
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ clone->mMsgHdr = (ipcMessageHeader *) RTMemDup(mMsgHdr, mMsgHdr->mLen);
+#else
+ clone->mMsgHdr = (ipcMessageHeader *) malloc(mMsgHdr->mLen);
+ memcpy(clone->mMsgHdr, mMsgHdr, mMsgHdr->mLen);
+#endif
+ }
+ 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)
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ RTMemFree(mMsgHdr);
+#else
+ free(mMsgHdr);
+#endif
+ mMsgComplete = PR_FALSE;
+
+ // allocate message data
+ PRUint32 msgLen = IPC_MSG_HEADER_SIZE + dataLen;
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ mMsgHdr = (ipcMessageHeader *) RTMemAlloc(msgLen);
+#else
+ mMsgHdr = (ipcMessageHeader *) malloc(msgLen);
+#endif
+ 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
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ mMsgHdr = (ipcMessageHeader *) RTMemRealloc(mMsgHdr, MsgLen());
+#else
+ mMsgHdr = (ipcMessageHeader *) realloc(mMsgHdr, MsgLen());
+#endif
+ }
+ }
+ }
+ }
+ 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;
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ mMsgHdr = (ipcMessageHeader *) RTMemAlloc(msgLen);
+#else
+ mMsgHdr = (ipcMessageHeader *) malloc(msgLen);
+#endif
+ if (!mMsgHdr)
+ return PR_FAILURE;
+ memcpy(mMsgHdr, buf, bufLen);
+ mMsgOffset = bufLen;
+ *bytesRead = bufLen;
+ *complete = PR_FALSE;
+ return PR_SUCCESS;
+ }
+ else {
+ PRUint32 msgLen = *(PRUint32 *) buf;
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ mMsgHdr = (ipcMessageHeader *) RTMemAlloc(msgLen);
+#else
+ mMsgHdr = (ipcMessageHeader *) malloc(msgLen);
+#endif
+ 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/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h
new file mode 100644
index 00000000..c9f8f184
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h
@@ -0,0 +1,214 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef 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 defined below. default value of flags is
+// zero. protocol implementations should ignore unrecognized flags. 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)
+
+//
+// the IPC message protocol supports synchronous messages. these messages can
+// only be sent from a client to the daemon. a daemon module cannot send a
+// synchronous message. the client sets the SYNC_QUERY flag to indicate that
+// it is expecting a response with the SYNC_REPLY flag set.
+//
+#define IPC_MSG_FLAG_SYNC_QUERY (0x1)
+#define IPC_MSG_FLAG_SYNC_REPLY (0x2)
+
+//
+// a special flag to prevent repeated processing of the same message by two
+// or more selectors when walking through the queue of pending messages
+// in WaitTarget().
+//
+#define IPC_MSG_FLAG_IN_PROCESS (0x4)
+
+//-----------------------------------------------------------------------------
+// ipcMessage
+//-----------------------------------------------------------------------------
+
+class ipcMessage
+{
+public:
+ ipcMessage()
+ : mNext(NULL)
+ , mMetaData(0)
+ , mMsgHdr(NULL)
+ , mMsgOffset(0)
+ , mMsgComplete(PR_FALSE)
+ { }
+ ipcMessage(const nsID &target, const char *data, PRUint32 dataLen)
+ : mNext(NULL)
+ , mMetaData(0)
+ , mMsgHdr(NULL)
+ , mMsgOffset(0)
+ { Init(target, data, dataLen); }
+ ~ipcMessage() NS_HIDDEN;
+
+ //
+ // reset message to uninitialized state
+ //
+ NS_HIDDEN_(void) Reset();
+
+ //
+ // create a copy of this message
+ //
+ NS_HIDDEN_(ipcMessage *) Clone() const;
+
+ //
+ // initialize message
+ //
+ // param:
+ // topic - message topic string
+ // data - message data (may be null to leave data uninitialized)
+ // dataLen - message data len
+ //
+ NS_HIDDEN_(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 any portion of the message's data.
+ //
+ // param:
+ // offset - destination offset
+ // data - data to write
+ // dataLen - number of bytes to write
+ //
+ NS_HIDDEN_(PRStatus) SetData(PRUint32 offset, const char *data, PRUint32 dataLen);
+
+ //
+ // access message flags
+ //
+ void SetFlag(PRUint16 flag) { mMsgHdr->mFlags |= flag; }
+ void ClearFlag(PRUint16 flag) { mMsgHdr->mFlags &= ~flag; }
+ PRBool TestFlag(PRUint16 flag) const { return mMsgHdr->mFlags & flag; }
+
+ //
+ // 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
+ //
+ NS_HIDDEN_(PRBool) Equals(const nsID &target, const char *data, PRUint32 dataLen) const;
+ NS_HIDDEN_(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.
+ //
+ NS_HIDDEN_(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.
+ //
+ NS_HIDDEN_(PRStatus) ReadFrom(const char *buf,
+ PRUint32 bufLen,
+ PRUint32 *bytesRead,
+ PRBool *complete);
+
+ //
+ // a message can be added to a singly-linked list.
+ //
+ class ipcMessage *mNext;
+
+ //
+ // meta data associated with this message object. the owner of the
+ // ipcMessage object is free to use this field for any purpose. by
+ // default, it is initialized to 0.
+ //
+ PRUint32 mMetaData;
+
+private:
+ ipcMessageHeader *mMsgHdr;
+
+ // XXX document me
+ PRUint32 mMsgOffset;
+ PRPackedBool mMsgComplete;
+};
+
+#endif // !ipcMessage_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp
new file mode 100644
index 00000000..08753ddb
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp
@@ -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 <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string.h>
+#include "ipcMessagePrimitives.h"
+
+ipcMessage_DWORD_STR::ipcMessage_DWORD_STR(const nsID &target,
+ PRUint32 first,
+ const char *second)
+{
+ int sLen = strlen(second);
+ Init(target, NULL, 4 + sLen + 1);
+ SetData(0, (char *) &first, 4);
+ SetData(4, second, sLen + 1);
+}
+
+ipcMessage_DWORD_DWORD_STR::ipcMessage_DWORD_DWORD_STR(const nsID &target,
+ PRUint32 first,
+ PRUint32 second,
+ const char *third)
+{
+ int sLen = strlen(third);
+ Init(target, NULL, 8 + sLen + 1);
+ SetData(0, (char *) &first, 4);
+ SetData(4, (char *) &second, 4);
+ SetData(8, third, sLen + 1);
+}
+
+ipcMessage_DWORD_ID::ipcMessage_DWORD_ID(const nsID &target,
+ PRUint32 first,
+ const nsID &second)
+{
+ Init(target, NULL, 4 + sizeof(nsID));
+ SetData(0, (char *) &first, 4);
+ SetData(4, (char *) &second, sizeof(nsID));
+}
+
+ipcMessage_DWORD_DWORD_ID::ipcMessage_DWORD_DWORD_ID(const nsID &target,
+ PRUint32 first,
+ PRUint32 second,
+ const nsID &third)
+{
+ Init(target, NULL, 8 + sizeof(nsID));
+ SetData(0, (char *) &first, 4);
+ SetData(4, (char *) &second, 4);
+ SetData(8, (char *) &third, sizeof(nsID));
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.h
new file mode 100644
index 00000000..abfa7d69
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.h
@@ -0,0 +1,206 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcMessagePrimitives_h__
+#define ipcMessagePrimitives_h__
+
+#include "ipcMessage.h"
+
+class ipcMessage_DWORD : public ipcMessage
+{
+public:
+ ipcMessage_DWORD(const nsID &target, PRUint32 first)
+ {
+ Init(target, (char *) &first, sizeof(first));
+ }
+
+ PRUint32 First() const
+ {
+ return ((PRUint32 *) Data())[0];
+ }
+};
+
+class ipcMessage_DWORD_DWORD : public ipcMessage
+{
+public:
+ ipcMessage_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second)
+ {
+ PRUint32 data[2] = { first, second };
+ Init(target, (char *) data, sizeof(data));
+ }
+
+ PRUint32 First() const
+ {
+ return ((PRUint32 *) Data())[0];
+ }
+
+ PRUint32 Second() const
+ {
+ return ((PRUint32 *) Data())[1];
+ }
+};
+
+class ipcMessage_DWORD_DWORD_DWORD : public ipcMessage
+{
+public:
+ ipcMessage_DWORD_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second, PRUint32 third)
+ {
+ PRUint32 data[3] = { first, second, third };
+ Init(target, (char *) data, sizeof(data));
+ }
+
+ PRUint32 First() const
+ {
+ return ((PRUint32 *) Data())[0];
+ }
+
+ PRUint32 Second() const
+ {
+ return ((PRUint32 *) Data())[1];
+ }
+
+ PRUint32 Third() const
+ {
+ return ((PRUint32 *) Data())[2];
+ }
+};
+
+class ipcMessage_DWORD_DWORD_DWORD_DWORD : public ipcMessage
+{
+public:
+ ipcMessage_DWORD_DWORD_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second, PRUint32 third, PRUint32 fourth)
+ {
+ PRUint32 data[4] = { first, second, third, fourth };
+ Init(target, (char *) data, sizeof(data));
+ }
+
+ PRUint32 First() const
+ {
+ return ((PRUint32 *) Data())[0];
+ }
+
+ PRUint32 Second() const
+ {
+ return ((PRUint32 *) Data())[1];
+ }
+
+ PRUint32 Third() const
+ {
+ return ((PRUint32 *) Data())[2];
+ }
+
+ PRUint32 Fourth() const
+ {
+ return ((PRUint32 *) Data())[3];
+ }
+};
+
+class ipcMessage_DWORD_STR : public ipcMessage
+{
+public:
+ ipcMessage_DWORD_STR(const nsID &target, PRUint32 first, const char *second) NS_HIDDEN;
+
+ PRUint32 First() const
+ {
+ return ((PRUint32 *) Data())[0];
+ }
+
+ const char *Second() const
+ {
+ return Data() + sizeof(PRUint32);
+ }
+};
+
+class ipcMessage_DWORD_DWORD_STR : public ipcMessage
+{
+public:
+ ipcMessage_DWORD_DWORD_STR(const nsID &target, PRUint32 first, PRUint32 second, const char *third) NS_HIDDEN;
+
+ PRUint32 First() const
+ {
+ return ((PRUint32 *) Data())[0];
+ }
+
+ PRUint32 Second() const
+ {
+ return ((PRUint32 *) Data())[1];
+ }
+
+ const char *Third() const
+ {
+ return Data() + 2 * sizeof(PRUint32);
+ }
+};
+
+class ipcMessage_DWORD_ID : public ipcMessage
+{
+public:
+ ipcMessage_DWORD_ID(const nsID &target, PRUint32 first, const nsID &second) NS_HIDDEN;
+
+ PRUint32 First() const
+ {
+ return ((PRUint32 *) Data())[0];
+ }
+
+ const nsID &Second() const
+ {
+ return * (const nsID *) (Data() + sizeof(PRUint32));
+ }
+};
+
+class ipcMessage_DWORD_DWORD_ID : public ipcMessage
+{
+public:
+ ipcMessage_DWORD_DWORD_ID(const nsID &target, PRUint32 first, PRUint32 second, const nsID &third) NS_HIDDEN;
+
+ PRUint32 First() const
+ {
+ return ((PRUint32 *) Data())[0];
+ }
+
+ PRUint32 Second() const
+ {
+ return ((PRUint32 *) Data())[1];
+ }
+
+ const nsID &Third() const
+ {
+ return * (const nsID *) (Data() + 2 * sizeof(PRUint32));
+ }
+};
+
+#endif // !ipcMessagePrimitives_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h
new file mode 100644
index 00000000..d372713e
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h
@@ -0,0 +1,46 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcMessageQ_h__
+#define ipcMessageQ_h__
+
+#include "ipcMessage.h"
+#include "ipcList.h"
+
+typedef ipcList<ipcMessage> ipcMessageQ;
+
+#endif // !ipcMessageQ_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageUtils.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageUtils.h
new file mode 100644
index 00000000..99e3e6b8
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageUtils.h
@@ -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 <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcMessageUtils_h__
+#define ipcMessageUtils_h__
+
+class ipcMessage;
+
+//
+// given code like this:
+//
+// const ipcmMessageClientID *msg = (const ipcmMessageClientID *) rawMsg;
+//
+// we can write:
+//
+// ipcMessageCast<ipcmMessageClientID> msg(rawMsg);
+//
+// XXX ipcMessageCast is probably not the best name for this class.
+//
+template<class T>
+class ipcMessageCast
+{
+public:
+ ipcMessageCast() : mPtr(NULL) {}
+ ipcMessageCast(const ipcMessage *ptr) : mPtr((const T *) ptr) {}
+ void operator=(const ipcMessage *ptr) { mPtr = (const T *) ptr; }
+ const T *operator->() { return mPtr; }
+private:
+ const T *mPtr;
+};
+
+#endif // !ipcMessageUtils_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.cpp
new file mode 100644
index 00000000..5464f9a7
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.cpp
@@ -0,0 +1,80 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcStringList.h"
+
+void *
+ipcStringNode::operator new(size_t size, const char *str) CPP_THROW_NEW
+{
+ int len = strlen(str);
+
+ size += len;
+
+ ipcStringNode *node = (ipcStringNode *) ::operator new(size);
+ if (!node)
+ return NULL;
+
+ node->mNext = NULL;
+ memcpy(node->mData, str, len);
+ node->mData[len] = '\0';
+
+ return node;
+}
+
+ipcStringNode *
+ipcStringList::FindNode(ipcStringNode *node, const char *str)
+{
+ while (node) {
+ if (node->Equals(str))
+ return node;
+ node = node->mNext;
+ }
+ return NULL;
+}
+
+ipcStringNode *
+ipcStringList::FindNodeBefore(ipcStringNode *node, const char *str)
+{
+ ipcStringNode *prev = NULL;
+ while (node) {
+ if (node->Equals(str))
+ return prev;
+ prev = node;
+ node = node->mNext;
+ }
+ return NULL;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h
new file mode 100644
index 00000000..2a2316b6
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h
@@ -0,0 +1,114 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcStringList_h__
+#define ipcStringList_h__
+
+#include <string.h>
+#include "plstr.h"
+#include "nscore.h"
+#include "ipcList.h"
+
+//-----------------------------------------------------------------------------
+// string node
+//-----------------------------------------------------------------------------
+
+class ipcStringNode
+{
+public:
+ ipcStringNode() {}
+
+ const char *Value() const { return mData; }
+
+ PRBool Equals(const char *val) const { return strcmp(mData, val) == 0; }
+ PRBool EqualsIgnoreCase(const char *val) const { return PL_strcasecmp(mData, val) == 0; }
+
+ class ipcStringNode *mNext;
+private:
+ void *operator new(size_t size, const char *str) CPP_THROW_NEW;
+
+ // this is actually bigger
+ char mData[1];
+
+ friend class ipcStringList;
+};
+
+//-----------------------------------------------------------------------------
+// singly-linked list of strings
+//-----------------------------------------------------------------------------
+
+class ipcStringList : public ipcList<ipcStringNode>
+{
+public:
+ typedef ipcList<ipcStringNode> Super;
+
+ void Prepend(const char *str)
+ {
+ Super::Prepend(new (str) ipcStringNode());
+ }
+
+ void Append(const char *str)
+ {
+ Super::Append(new (str) ipcStringNode());
+ }
+
+ const ipcStringNode *Find(const char *str) const
+ {
+ return FindNode(mHead, str);
+ }
+
+ PRBool FindAndDelete(const char *str)
+ {
+ ipcStringNode *node = FindNodeBefore(mHead, str);
+ if (node) {
+ DeleteAfter(node);
+ return PR_TRUE;
+ }
+ else if (!IsEmpty()) {
+ DeleteFirst();
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+ }
+
+private:
+ static NS_HIDDEN_(ipcStringNode *) FindNode (ipcStringNode *head, const char *str);
+ static NS_HIDDEN_(ipcStringNode *) FindNodeBefore(ipcStringNode *head, const char *str);
+};
+
+#endif // !ipcStringList_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp
new file mode 100644
index 00000000..7f7ed060
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp
@@ -0,0 +1,303 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string.h>
+#include "ipcm.h"
+#include "pratom.h"
+
+const nsID IPCM_TARGET =
+{ /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */
+ 0x753ca8ff,
+ 0xc8c2,
+ 0x4601,
+ {0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50}
+};
+
+PRUint32
+IPCM_NewRequestIndex()
+{
+ static PRInt32 sRequestIndex;
+ return (PRUint32) PR_AtomicIncrement(&sRequestIndex);
+}
+
+#if 0
+
+//
+// MSG_TYPE values
+//
+const PRUint32 ipcmMessagePing::MSG_TYPE = IPCM_MSG_TYPE_PING;
+const PRUint32 ipcmMessageError::MSG_TYPE = IPCM_MSG_TYPE_ERROR;
+const PRUint32 ipcmMessageClientHello::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_HELLO;
+const PRUint32 ipcmMessageClientID::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ID;
+const PRUint32 ipcmMessageClientInfo::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_INFO;
+const PRUint32 ipcmMessageClientAddName::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ADD_NAME;
+const PRUint32 ipcmMessageClientDelName::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_DEL_NAME;
+const PRUint32 ipcmMessageClientAddTarget::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ADD_TARGET;
+const PRUint32 ipcmMessageClientDelTarget::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_DEL_TARGET;
+const PRUint32 ipcmMessageQueryClientByName::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME;
+const PRUint32 ipcmMessageQueryClientInfo::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_INFO;
+const PRUint32 ipcmMessageForward::MSG_TYPE = IPCM_MSG_TYPE_FORWARD;
+const PRUint32 ipcmMessageClientStatus::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_STATUS;
+
+//
+// CLIENT_INFO message
+//
+// +-----------------------------------------+
+// | DWORD : MSG_TYPE |
+// +--------------------+--------------------+
+// | DWORD : clientID |
+// +--------------------+--------------------+
+// | DWORD : requestIndex |
+// +--------------------+--------------------+
+// | WORD : nameStart | WORD : nameCount |
+// +--------------------+--------------------+
+// | WORD : targetStart | WORD : targetCount |
+// +--------------------+--------------------+
+// | name[0] | (null byte) |
+// +--------------------+--------------------+
+// . . .
+// . . .
+// +--------------------+--------------------+
+// | name[count - 1] | (null byte) |
+// +--------------------+--------------------+
+// | target[0] |
+// +-----------------------------------------+
+// . . .
+// . . .
+// +-----------------------------------------+
+// | target[count - 1] |
+// +-----------------------------------------+
+//
+
+struct ipcmClientInfoHeader
+{
+ PRUint32 mType;
+ PRUint32 mID;
+ PRUint32 mRequestIndex;
+ PRUint16 mNameStart;
+ PRUint16 mNameCount;
+ PRUint16 mTargetStart;
+ PRUint16 mTargetCount;
+};
+
+ipcmMessageClientInfo::ipcmMessageClientInfo(PRUint32 cID, PRUint32 rIdx, const char *names[], const nsID *targets[])
+{
+ ipcmClientInfoHeader hdr = {0};
+
+ hdr.mType = MSG_TYPE;
+ hdr.mID = cID;
+ hdr.mRequestIndex = rIdx;
+ hdr.mNameStart = sizeof(hdr);
+
+ PRUint32 i, namesLen = 0;
+
+ i = 0;
+ while (names[i]) {
+ namesLen += (strlen(names[i]) + 1);
+ ++hdr.mNameCount;
+ ++i;
+ }
+
+ i = 0;
+ while (targets[i]) {
+ ++hdr.mTargetCount;
+ ++i;
+ }
+
+ //
+ // compute target array starting offset
+ //
+ hdr.mTargetStart = hdr.mNameStart + namesLen;
+
+ //
+ // compute message length
+ //
+ PRUint32 dataLen = sizeof(hdr) + namesLen + hdr.mTargetCount * sizeof(nsID);
+
+ Init(IPCM_TARGET, NULL, dataLen);
+
+ //
+ // write message data
+ //
+ SetData(0, (const char *) &hdr, sizeof(hdr));
+
+ PRUint32 offset = sizeof(hdr);
+
+ for (i = 0; names[i]; ++i) {
+ PRUint32 len = strlen(names[i]) + 1;
+ SetData(offset, names[i], len);
+ offset += len;
+ }
+
+ for (i = 0; targets[i]; ++i) {
+ PRUint32 len = sizeof(nsID);
+ SetData(offset, (const char *) targets[i], len);
+ offset += len;
+ }
+}
+
+PRUint32
+ipcmMessageClientInfo::ClientID() const
+{
+ ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
+ return hdr->mID;
+}
+
+PRUint32
+ipcmMessageClientInfo::RequestIndex() const
+{
+ ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
+ return hdr->mRequestIndex;
+}
+
+PRUint32
+ipcmMessageClientInfo::NameCount() const
+{
+ ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
+ return hdr->mNameCount;
+}
+
+PRUint32
+ipcmMessageClientInfo::TargetCount() const
+{
+ ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
+ return hdr->mTargetCount;
+}
+
+const char *
+ipcmMessageClientInfo::NextName(const char *name) const
+{
+ ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
+
+ if (!name)
+ return (const char *) hdr + hdr->mNameStart;
+
+ name += strlen(name) + 1;
+ if (name == (const char *) hdr + hdr->mTargetStart)
+ name = NULL;
+ return name;
+}
+
+const nsID *
+ipcmMessageClientInfo::NextTarget(const nsID *target) const
+{
+ ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
+
+ if (!target)
+ return (const nsID *) (Data() + hdr->mTargetStart);
+
+ if (++target == (const nsID *) (MsgBuf() + MsgLen()))
+ target = NULL;
+ return target;
+}
+#endif
+
+//
+// FORWARD message
+//
+// +-------------------------+
+// | DWORD : MSG_TYPE |
+// +-------------------------+
+// | clientID |
+// +-------------------------+
+// | innerMsgHeader |
+// +-------------------------+
+// | innerMsgData |
+// +-------------------------+
+//
+
+ipcmMessageForward::ipcmMessageForward(PRUint32 type,
+ PRUint32 cID,
+ const nsID &target,
+ const char *data,
+ PRUint32 dataLen)
+{
+ int len = sizeof(ipcmMessageHeader) + // IPCM header
+ sizeof(cID) + // cID
+ IPC_MSG_HEADER_SIZE + // innerMsgHeader
+ dataLen; // innerMsgData
+
+ Init(IPCM_TARGET, NULL, len);
+
+ ipcmMessageHeader ipcmHdr =
+ { type, IPCM_NewRequestIndex() };
+
+ SetData(0, (char *) &ipcmHdr, sizeof(ipcmHdr));
+ SetData(sizeof(ipcmHdr), (char *) &cID, sizeof(cID));
+
+ ipcMessageHeader hdr;
+ hdr.mLen = IPC_MSG_HEADER_SIZE + dataLen;
+ hdr.mVersion = IPC_MSG_VERSION;
+ hdr.mFlags = 0;
+ hdr.mTarget = target;
+
+ SetData(sizeof(ipcmHdr) + sizeof(cID), (char *) &hdr, IPC_MSG_HEADER_SIZE);
+ if (data)
+ SetInnerData(0, data, dataLen);
+}
+
+void
+ipcmMessageForward::SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen)
+{
+ SetData(sizeof(ipcmMessageHeader) + 4 + IPC_MSG_HEADER_SIZE + offset, data, dataLen);
+}
+
+PRUint32
+ipcmMessageForward::ClientID() const
+{
+ return ((PRUint32 *) Data())[2];
+}
+
+const nsID &
+ipcmMessageForward::InnerTarget() const
+{
+ ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 12);
+ return hdr->mTarget;
+}
+
+const char *
+ipcmMessageForward::InnerData() const
+{
+ return Data() + 12 + IPC_MSG_HEADER_SIZE;
+}
+
+PRUint32
+ipcmMessageForward::InnerDataLen() const
+{
+ ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 12);
+ return hdr->mLen - IPC_MSG_HEADER_SIZE;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h
new file mode 100644
index 00000000..a6445654
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h
@@ -0,0 +1,502 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcm_h__
+#define ipcm_h__
+
+#include "ipcMessage.h"
+#include "ipcMessagePrimitives.h"
+
+//-----------------------------------------------------------------------------
+
+//
+// IPCM (IPC Manager) protocol support
+//
+
+// The IPCM message target identifier:
+extern const nsID IPCM_TARGET;
+
+//
+// Every IPCM message has the following structure:
+//
+// +-----------------------------------------+
+// | (ipc message header) |
+// +-----------------------------------------+
+// | DWORD : type |
+// +-----------------------------------------+
+// | DWORD : requestIndex |
+// +-----------------------------------------+
+// . .
+// . (payload) .
+// . .
+// +-----------------------------------------+
+//
+// where |type| is an integer uniquely identifying the message. the type is
+// composed of a message class identifier and a message number. there are 3
+// message classes:
+//
+// ACK - acknowledging a request
+// REQ - making a request
+// PSH - providing unrequested, "pushed" information
+//
+// The requestIndex field is initialized when a request is made. An
+// acknowledgement's requestIndex is equal to that of its corresponding
+// request message. This enables the requesting side of the message exchange
+// to match acknowledgements to requests. The requestIndex field is ignored
+// for PSH messages.
+//
+
+// The IPCM message class is stored in the most significant byte.
+#define IPCM_MSG_CLASS_REQ (1 << 24)
+#define IPCM_MSG_CLASS_ACK (2 << 24)
+#define IPCM_MSG_CLASS_PSH (4 << 24)
+
+// Requests
+#define IPCM_MSG_REQ_PING (IPCM_MSG_CLASS_REQ | 1)
+#define IPCM_MSG_REQ_FORWARD (IPCM_MSG_CLASS_REQ | 2)
+#define IPCM_MSG_REQ_CLIENT_HELLO (IPCM_MSG_CLASS_REQ | 3)
+#define IPCM_MSG_REQ_CLIENT_ADD_NAME (IPCM_MSG_CLASS_REQ | 4)
+#define IPCM_MSG_REQ_CLIENT_DEL_NAME (IPCM_MSG_CLASS_REQ | 5)
+#define IPCM_MSG_REQ_CLIENT_ADD_TARGET (IPCM_MSG_CLASS_REQ | 6)
+#define IPCM_MSG_REQ_CLIENT_DEL_TARGET (IPCM_MSG_CLASS_REQ | 7)
+#define IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME (IPCM_MSG_CLASS_REQ | 8)
+#define IPCM_MSG_REQ_QUERY_CLIENT_NAMES (IPCM_MSG_CLASS_REQ | 9) // TODO
+#define IPCM_MSG_REQ_QUERY_CLIENT_TARGETS (IPCM_MSG_CLASS_REQ | 10) // TODO
+
+// Acknowledgements
+#define IPCM_MSG_ACK_RESULT (IPCM_MSG_CLASS_ACK | 1)
+#define IPCM_MSG_ACK_CLIENT_ID (IPCM_MSG_CLASS_ACK | 2)
+#define IPCM_MSG_ACK_CLIENT_NAMES (IPCM_MSG_CLASS_ACK | 3) // TODO
+#define IPCM_MSG_ACK_CLIENT_TARGETS (IPCM_MSG_CLASS_ACK | 4) // TODO
+
+// Push messages
+#define IPCM_MSG_PSH_CLIENT_STATE (IPCM_MSG_CLASS_PSH | 1)
+#define IPCM_MSG_PSH_FORWARD (IPCM_MSG_CLASS_PSH | 2)
+
+//-----------------------------------------------------------------------------
+
+//
+// IPCM header
+//
+struct ipcmMessageHeader
+{
+ PRUint32 mType;
+ PRUint32 mRequestIndex;
+};
+
+//
+// returns IPCM message type.
+//
+static inline int
+IPCM_GetType(const ipcMessage *msg)
+{
+ return ((const ipcmMessageHeader *) msg->Data())->mType;
+}
+
+//
+// return IPCM message request index.
+//
+static inline PRUint32
+IPCM_GetRequestIndex(const ipcMessage *msg)
+{
+ return ((const ipcmMessageHeader *) msg->Data())->mRequestIndex;
+}
+
+//
+// return a request index that is unique to this process.
+//
+NS_HIDDEN_(PRUint32)
+IPCM_NewRequestIndex();
+
+//-----------------------------------------------------------------------------
+
+//
+// The IPCM protocol is detailed below:
+//
+
+// REQUESTS
+
+//
+// req: IPCM_MSG_REQ_PING
+// ack: IPCM_MSG_ACK_RESULT
+//
+// A PING can be sent from either a client to the daemon, or from the daemon
+// to a client. The expected acknowledgement is a RESULT message with a status
+// code of 0.
+//
+// This request message has no payload.
+//
+
+//
+// req: IPCM_MSG_REQ_FORWARD
+// ack: IPCM_MSG_ACK_RESULT
+//
+// A FORWARD is sent when a client wishes to send a message to another client.
+// The payload of this message is another message that should be forwarded by
+// the daemon's IPCM to the specified client. The expected acknowledgment is
+// a RESULT message with a status code indicating success or failure.
+//
+// When the daemon receives a FORWARD message, it creates a PSH_FORWARD message
+// and sends that on to the destination client.
+//
+// This request message has as its payload:
+//
+// +-----------------------------------------+
+// | DWORD : clientID |
+// +-----------------------------------------+
+// | (innerMsgHeader) |
+// +-----------------------------------------+
+// | (innerMsgData) |
+// +-----------------------------------------+
+//
+
+//
+// req: IPCM_MSG_REQ_CLIENT_HELLO
+// ack: IPCM_MSG_REQ_CLIENT_ID <or> IPCM_MSG_REQ_RESULT
+//
+// A CLIENT_HELLO is sent when a client connects to the IPC daemon. The
+// expected acknowledgement is a CLIENT_ID message informing the new client of
+// its ClientID. If for some reason the IPC daemon cannot accept the new
+// client, it returns a RESULT message with a failure status code.
+//
+// This request message has no payload.
+//
+
+//
+// req: IPCM_MSG_REQ_CLIENT_ADD_NAME
+// ack: IPCM_MSG_ACK_RESULT
+//
+// A CLIENT_ADD_NAME is sent when a client wishes to register an additional
+// name for itself. The expected acknowledgement is a RESULT message with a
+// status code indicating success or failure.
+//
+// This request message has as its payload a null-terminated ASCII character
+// string indicating the name of the client.
+//
+
+//
+// req: IPCM_MSG_REQ_CLIENT_DEL_NAME
+// ack: IPCM_MSG_ACK_RESULT
+//
+// A CLIENT_DEL_NAME is sent when a client wishes to unregister a name that it
+// has registered. The expected acknowledgement is a RESULT message with a
+// status code indicating success or failure.
+//
+// This request message has as its payload a null-terminated ASCII character
+// string indicating the name of the client.
+//
+
+//
+// req: IPCM_MSG_REQ_CLIENT_ADD_TARGET
+// ack: IPCM_MSG_ACK_RESULT
+//
+// A CLIENT_ADD_TARGET is sent when a client wishes to register an additional
+// target that it supports. The expected acknowledgement is a RESULT message
+// with a status code indicating success or failure.
+//
+// This request message has as its payload a 128-bit UUID indicating the
+// target to add.
+//
+
+//
+// req: IPCM_MSG_REQ_CLIENT_DEL_TARGET
+// ack: IPCM_MSG_ACK_RESULT
+//
+// A CLIENT_DEL_TARGET is sent when a client wishes to unregister a target
+// that it has registered. The expected acknowledgement is a RESULT message
+// with a status code indicating success or failure.
+//
+// This request message has as its payload a 128-bit UUID indicating the
+// target to remove.
+//
+
+//
+// req: IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME
+// ack: IPCM_MSG_ACK_CLIENT_ID <or> IPCM_MSG_ACK_RESULT
+//
+// A QUERY_CLIENT_BY_NAME may be sent by a client to discover the client that
+// is known by a common name. If more than one client matches the name, then
+// only the ID of the more recently registered client is returned. The
+// expected acknowledgement is a CLIENT_ID message carrying the ID of the
+// corresponding client. If no client matches the given name or if some error
+// occurs, then a RESULT message with a failure status code is returned.
+//
+// This request message has as its payload a null-terminated ASCII character
+// string indicating the client name to query.
+//
+
+// ACKNOWLEDGEMENTS
+
+//
+// ack: IPCM_MSG_ACK_RESULT
+//
+// This acknowledgement is returned to indicate a success or failure status.
+//
+// The payload consists of a single DWORD value.
+//
+// Possible status codes are listed below (negative values indicate failure
+// codes):
+//
+#define IPCM_OK 0 // success: generic
+#define IPCM_ERROR_GENERIC -1 // failure: generic
+#define IPCM_ERROR_NO_CLIENT -2 // failure: client does not exist
+#define IPCM_ERROR_INVALID_ARG -3 // failure: invalid request argument
+#define IPCM_ERROR_NO_SUCH_DATA -4 // failure: requested data does not exist
+#define IPCM_ERROR_ALREADY_EXISTS -5 // failure: data to set already exists
+
+//
+// ack: IPCM_MSG_ACK_CLIENT_ID
+//
+// This acknowledgement is returned to specify a client ID.
+//
+// The payload consists of a single DWORD value.
+//
+
+// PUSH MESSAGES
+
+//
+// psh: ICPM_MSG_PSH_CLIENT_STATE
+//
+// This message is sent to clients to indicate the status of other clients.
+//
+// The payload consists of:
+//
+// +-----------------------------------------+
+// | DWORD : clientID |
+// +-----------------------------------------+
+// | DWORD : clientState |
+// +-----------------------------------------+
+//
+// where, clientState is one of the following values indicating whether the
+// client has recently connected (up) or disconnected (down):
+//
+#define IPCM_CLIENT_STATE_UP 1
+#define IPCM_CLIENT_STATE_DOWN 2
+
+//
+// psh: IPCM_MSG_PSH_FORWARD
+//
+// This message is sent by the daemon to a client on behalf of another client.
+// The recipient is expected to unpack the contained message and process it.
+//
+// The payload of this message matches the payload of IPCM_MSG_REQ_FORWARD,
+// with the exception that the clientID field is set to the clientID of the
+// sender of the IPCM_MSG_REQ_FORWARD message.
+//
+
+//-----------------------------------------------------------------------------
+
+//
+// NOTE: This file declares some helper classes that simplify constructing
+// and parsing 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 ipcmMessageClientHello("foo");
+//
+// Given an arbitrary ipcMessage, it can be parsed using logic similar
+// to the following:
+//
+// void func(const ipcMessage *unknown)
+// {
+// if (unknown->Topic().Equals(IPCM_TARGET)) {
+// if (IPCM_GetMsgType(unknown) == IPCM_MSG_TYPE_CLIENT_ID) {
+// ipcMessageCast<ipcmMessageClientID> msg(unknown);
+// printf("Client ID: %u\n", msg->ClientID());
+// }
+// }
+// }
+//
+
+// REQUESTS
+
+class ipcmMessagePing : public ipcMessage_DWORD_DWORD
+{
+public:
+ ipcmMessagePing()
+ : ipcMessage_DWORD_DWORD(
+ IPCM_TARGET,
+ IPCM_MSG_REQ_PING,
+ IPCM_NewRequestIndex()) {}
+};
+
+class ipcmMessageForward : public ipcMessage
+{
+public:
+ // @param type the type of this message: IPCM_MSG_{REQ,PSH}_FORWARD
+ // @param clientID the client id of the sender or receiver
+ // @param target the message target
+ // @param data the message data
+ // @param dataLen the message data length
+ ipcmMessageForward(PRUint32 type,
+ PRUint32 clientID,
+ const nsID &target,
+ const char *data,
+ PRUint32 dataLen) NS_HIDDEN;
+
+ // set inner message data, constrained to the data length passed
+ // to this class's constructor.
+ NS_HIDDEN_(void) SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen);
+
+ NS_HIDDEN_(PRUint32) ClientID() const;
+ NS_HIDDEN_(const nsID &) InnerTarget() const;
+ NS_HIDDEN_(const char *) InnerData() const;
+ NS_HIDDEN_(PRUint32) InnerDataLen() const;
+};
+
+class ipcmMessageClientHello : public ipcMessage_DWORD_DWORD
+{
+public:
+ ipcmMessageClientHello()
+ : ipcMessage_DWORD_DWORD(
+ IPCM_TARGET,
+ IPCM_MSG_REQ_CLIENT_HELLO,
+ IPCM_NewRequestIndex()) {}
+};
+
+class ipcmMessageClientAddName : public ipcMessage_DWORD_DWORD_STR
+{
+public:
+ ipcmMessageClientAddName(const char *name)
+ : ipcMessage_DWORD_DWORD_STR(
+ IPCM_TARGET,
+ IPCM_MSG_REQ_CLIENT_ADD_NAME,
+ IPCM_NewRequestIndex(),
+ name) {}
+
+ const char *Name() const { return Third(); }
+};
+
+class ipcmMessageClientDelName : public ipcMessage_DWORD_DWORD_STR
+{
+public:
+ ipcmMessageClientDelName(const char *name)
+ : ipcMessage_DWORD_DWORD_STR(
+ IPCM_TARGET,
+ IPCM_MSG_REQ_CLIENT_DEL_NAME,
+ IPCM_NewRequestIndex(),
+ name) {}
+
+ const char *Name() const { return Third(); }
+};
+
+class ipcmMessageClientAddTarget : public ipcMessage_DWORD_DWORD_ID
+{
+public:
+ ipcmMessageClientAddTarget(const nsID &target)
+ : ipcMessage_DWORD_DWORD_ID(
+ IPCM_TARGET,
+ IPCM_MSG_REQ_CLIENT_ADD_TARGET,
+ IPCM_NewRequestIndex(),
+ target) {}
+
+ const nsID &Target() const { return Third(); }
+};
+
+class ipcmMessageClientDelTarget : public ipcMessage_DWORD_DWORD_ID
+{
+public:
+ ipcmMessageClientDelTarget(const nsID &target)
+ : ipcMessage_DWORD_DWORD_ID(
+ IPCM_TARGET,
+ IPCM_MSG_REQ_CLIENT_ADD_TARGET,
+ IPCM_NewRequestIndex(),
+ target) {}
+
+ const nsID &Target() const { return Third(); }
+};
+
+class ipcmMessageQueryClientByName : public ipcMessage_DWORD_DWORD_STR
+{
+public:
+ ipcmMessageQueryClientByName(const char *name)
+ : ipcMessage_DWORD_DWORD_STR(
+ IPCM_TARGET,
+ IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME,
+ IPCM_NewRequestIndex(),
+ name) {}
+
+ const char *Name() const { return Third(); }
+ PRUint32 RequestIndex() const { return Second(); }
+};
+
+// ACKNOWLEDGEMENTS
+
+class ipcmMessageResult : public ipcMessage_DWORD_DWORD_DWORD
+{
+public:
+ ipcmMessageResult(PRUint32 requestIndex, PRInt32 status)
+ : ipcMessage_DWORD_DWORD_DWORD(
+ IPCM_TARGET,
+ IPCM_MSG_ACK_RESULT,
+ requestIndex,
+ (PRUint32) status) {}
+
+ PRInt32 Status() const { return (PRInt32) Third(); }
+};
+
+class ipcmMessageClientID : public ipcMessage_DWORD_DWORD_DWORD
+{
+public:
+ ipcmMessageClientID(PRUint32 requestIndex, PRUint32 clientID)
+ : ipcMessage_DWORD_DWORD_DWORD(
+ IPCM_TARGET,
+ IPCM_MSG_ACK_CLIENT_ID,
+ requestIndex,
+ clientID) {}
+
+ PRUint32 ClientID() const { return Third(); }
+};
+
+// PUSH MESSAGES
+
+class ipcmMessageClientState : public ipcMessage_DWORD_DWORD_DWORD_DWORD
+{
+public:
+ ipcmMessageClientState(PRUint32 clientID, PRUint32 clientStatus)
+ : ipcMessage_DWORD_DWORD_DWORD_DWORD(
+ IPCM_TARGET,
+ IPCM_MSG_PSH_CLIENT_STATE,
+ 0,
+ clientID,
+ clientStatus) {}
+
+ PRUint32 ClientID() const { return Third(); }
+ PRUint32 ClientState() const { return Fourth(); }
+};
+
+#endif // !ipcm_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore
new file mode 100644
index 00000000..d1a44d27
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+TestIPC
diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in
new file mode 100644
index 00000000..bad636f3
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in
@@ -0,0 +1,69 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS = module
+
+MODULE = ipcd_test
+REQUIRES = \
+ xpcom \
+ string \
+ ipcd \
+ $(NULL)
+
+CPPSRCS = \
+ TestIPC.cpp \
+ $(NULL)
+
+SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
+
+include $(topsrcdir)/config/config.mk
+
+LIBS = \
+ $(EXTRA_DSO_LIBS) \
+ $(XPCOM_LIBS) \
+ $(NSPR_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp b/src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp
new file mode 100644
index 00000000..1100d674
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp
@@ -0,0 +1,338 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Darin Fisher <darin@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcIService.h"
+#include "ipcIMessageObserver.h"
+#include "ipcILockService.h"
+#include "ipcCID.h"
+#include "ipcLockCID.h"
+
+#include "nsIEventQueueService.h"
+#include "nsIServiceManager.h"
+#include "nsIComponentRegistrar.h"
+
+#include "nsString.h"
+#include "prmem.h"
+
+static const nsID kIPCMTargetID =
+{ /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */
+ 0x753ca8ff,
+ 0xc8c2,
+ 0x4601,
+ {0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50}
+};
+
+static const nsID kTestTargetID =
+{ /* 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 ipcIService *gIpcServ = nsnull;
+static ipcILockService *gIpcLockServ = nsnull;
+
+static void
+SendMsg(ipcIService *ipc, PRUint32 cID, const nsID &target, const char *data, PRUint32 dataLen, PRBool sync = PR_FALSE)
+{
+ printf("*** sending message: [to-client=%u dataLen=%u]\n", cID, dataLen);
+
+ nsresult rv;
+
+ rv = ipc->SendMessage(cID, target, (const PRUint8 *) data, dataLen);
+ if (NS_FAILED(rv)) {
+ printf("*** sending message failed: rv=%x\n", rv);
+ return;
+ }
+
+ if (sync) {
+ rv = ipc->WaitMessage(cID, target, nsnull, PR_UINT32_MAX);
+ if (NS_FAILED(rv))
+ printf("*** waiting for message failed: rv=%x\n", rv);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+class myIpcMessageObserver : public ipcIMessageObserver
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_IPCIMESSAGEOBSERVER
+};
+NS_IMPL_ISUPPORTS1(myIpcMessageObserver, ipcIMessageObserver)
+
+NS_IMETHODIMP
+myIpcMessageObserver::OnMessageAvailable(PRUint32 sender, const nsID &target, const PRUint8 *data, PRUint32 dataLen)
+{
+ printf("*** got message: [sender=%u data=%s]\n", sender, (const char *) data);
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+
+#if 0
+class myIpcClientQueryHandler : public ipcIClientQueryHandler
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_IPCICLIENTQUERYHANDLER
+};
+
+NS_IMPL_ISUPPORTS1(myIpcClientQueryHandler, ipcIClientQueryHandler)
+
+NS_IMETHODIMP
+myIpcClientQueryHandler::OnQueryComplete(PRUint32 aQueryID,
+ nsresult aStatus,
+ PRUint32 aClientID,
+ const char **aNames,
+ PRUint32 aNameCount,
+ const nsID **aTargets,
+ PRUint32 aTargetCount)
+{
+ printf("*** query complete [queryID=%u status=0x%x clientID=%u]\n",
+ aQueryID, aStatus, aClientID);
+
+ PRUint32 i;
+ printf("*** names:\n");
+ for (i = 0; i < aNameCount; ++i)
+ printf("*** %d={%s}\n", i, aNames[i]);
+ printf("*** targets:\n");
+ for (i = 0; i < aTargetCount; ++i) {
+ const char *trailer;
+ if (aTargets[i]->Equals(kTestTargetID))
+ trailer = " (TEST_TARGET_ID)";
+ else if (aTargets[i]->Equals(kIPCMTargetID))
+ trailer = " (IPCM_TARGET_ID)";
+ else
+ trailer = " (unknown)";
+ char *str = aTargets[i]->ToString();
+ printf("*** %d=%s%s\n", i, str, trailer);
+ PR_Free(str);
+ }
+
+ if (aClientID != 0) {
+ const char hello[] = "hello friend!";
+ SendMsg(gIpcServ, aClientID, kTestTargetID, hello, sizeof(hello));
+ }
+
+ return NS_OK;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+
+#if 0
+class myIpcLockNotify : public ipcILockNotify
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_IPCILOCKNOTIFY
+};
+
+NS_IMPL_ISUPPORTS1(myIpcLockNotify, ipcILockNotify)
+
+NS_IMETHODIMP
+myIpcLockNotify::OnAcquireLockComplete(const char *lockName, nsresult status)
+{
+ printf("*** OnAcquireLockComplete [lock=%s status=%x]\n", lockName, status);
+ gIpcLockServ->ReleaseLock(lockName);
+ return NS_OK;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+
+int main(int argc, char **argv)
+{
+ nsresult rv;
+
+ {
+ nsCOMPtr<nsIServiceManager> servMan;
+ NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull);
+ nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
+ NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
+ if (registrar)
+ registrar->AutoRegister(nsnull);
+
+ // Create the Event Queue for this thread...
+ nsCOMPtr<nsIEventQueueService> 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");
+
+ printf("*** getting ipc service\n");
+ nsCOMPtr<ipcIService> ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv));
+ RETURN_IF_FAILED(rv, "do_GetService(ipcServ)");
+ NS_ADDREF(gIpcServ = ipcServ);
+
+ if (argc > 1) {
+ printf("*** using client name [%s]\n", argv[1]);
+ gIpcServ->AddName(argv[1]);
+ }
+
+ ipcServ->DefineTarget(kTestTargetID, new myIpcMessageObserver(), PR_TRUE);
+
+ 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, 0, kTestTargetID, data, sizeof(data), PR_TRUE);
+
+// PRUint32 queryID;
+// nsCOMPtr<ipcIClientQueryHandler> handler(new myIpcClientQueryHandler());
+// ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID);
+
+ PRUint32 foopyID;
+ nsresult foopyRv = ipcServ->ResolveClientName("foopy", &foopyID);
+ printf("*** query for 'foopy' returned [rv=%x id=%u]\n", foopyRv, foopyID);
+
+ if (NS_SUCCEEDED(foopyRv)) {
+ const char hello[] = "hello friend!";
+ SendMsg(ipcServ, foopyID, kTestTargetID, hello, sizeof(hello));
+ }
+
+ //
+ // test lock service
+ //
+ nsCOMPtr<ipcILockService> lockService = do_GetService(IPC_LOCKSERVICE_CONTRACTID, &rv);
+ RETURN_IF_FAILED(rv, "do_GetService(ipcLockServ)");
+ NS_ADDREF(gIpcLockServ = lockService);
+
+ //nsCOMPtr<ipcILockNotify> notify(new myIpcLockNotify());
+ gIpcLockServ->AcquireLock("blah", PR_TRUE);
+
+ rv = gIpcLockServ->AcquireLock("foo", PR_TRUE);
+ printf("*** sync AcquireLock returned [rv=%x]\n", rv);
+
+ PLEvent *ev;
+ while (gKeepRunning) {
+ gEventQ->WaitForEvent(&ev);
+ gEventQ->HandleEvent(ev);
+ }
+
+ NS_RELEASE(gIpcServ);
+
+ printf("*** processing remaining events\n");
+
+ // process any remaining events
+ 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/src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/module/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/test/module/Makefile.in
new file mode 100644
index 00000000..aec7c169
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/test/module/Makefile.in
@@ -0,0 +1,81 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2002
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Darin Fisher <darin@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd_test
+LIBRARY_NAME = testmodule
+SHORT_LIBNAME = testmod
+MODULE_NAME = ipcd_test
+
+FORCE_SHARED_LIB = 1
+NO_DIST_INSTALL = 1
+
+REQUIRES = \
+ xpcom \
+ ipcd \
+ $(NULL)
+
+CPPSRCS = TestModule.cpp
+
+LOCAL_INCLUDES = \
+ -I$(srcdir)/../common \
+ $(NULL)
+
+EXTRA_DSO_LDOPTS = \
+ $(LIBS_DIR) \
+ $(NSPR_LIBS) \
+ $(EXTRA_DSO_LIBS) \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
+_IPC_FILES = \
+ $(DLL_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/src/libs/xpcom18a4/ipc/ipcd/test/module/TestModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/test/module/TestModule.cpp
new file mode 100644
index 00000000..fbd78867
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/test/module/TestModule.cpp
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include "ipcModuleUtil.h"
+
+#define TEST_MODULE_ID \
+{ /* e628fc6e-a6a7-48c7-adba-f241d1128fb8 */ \
+ 0xe628fc6e, \
+ 0xa6a7, \
+ 0x48c7, \
+ {0xad, 0xba, 0xf2, 0x41, 0xd1, 0x12, 0x8f, 0xb8} \
+}
+static const nsID kTestModuleID = TEST_MODULE_ID;
+
+struct TestModule
+{
+ static void Init()
+ {
+ printf("*** TestModule::Init\n");
+ }
+
+ static void Shutdown()
+ {
+ printf("*** TestModule::Shutdown\n");
+ }
+
+ static void HandleMsg(ipcClientHandle client,
+ const nsID &target,
+ const void *data,
+ PRUint32 dataLen)
+ {
+ printf("*** TestModule::HandleMsg [%s]\n", (const char *) data);
+
+ static const char buf[] = "pong";
+ IPC_SendMsg(client, kTestModuleID, buf, sizeof(buf));
+ }
+
+ static void ClientUp(ipcClientHandle client)
+ {
+ printf("*** TestModule::ClientUp [%u]\n", IPC_GetClientID(client));
+ }
+
+ static void ClientDown(ipcClientHandle client)
+ {
+ printf("*** TestModule::ClientDown [%u]\n", IPC_GetClientID(client));
+ }
+};
+
+static ipcModuleMethods gTestMethods =
+{
+ IPC_MODULE_METHODS_VERSION,
+ TestModule::Init,
+ TestModule::Shutdown,
+ TestModule::HandleMsg,
+ TestModule::ClientUp,
+ TestModule::ClientDown
+};
+
+static ipcModuleEntry gTestModuleEntry[] =
+{
+ { TEST_MODULE_ID, &gTestMethods }
+};
+
+IPC_IMPL_GETMODULES(TestModule, gTestModuleEntry)
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in
new file mode 100644
index 00000000..323f87f8
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in
@@ -0,0 +1,49 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Conrad Carlen <ccarlen@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+DIRS = public src
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/util/public/Makefile.in
new file mode 100644
index 00000000..84d980c4
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/public/Makefile.in
@@ -0,0 +1,53 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Conrad Carlen <ccarlen@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+
+EXPORTS = \
+ ipcMessageReader.h \
+ ipcMessageWriter.h \
+ $(NULL)
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageReader.h b/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageReader.h
new file mode 100644
index 00000000..f93bfa20
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageReader.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Conrad Carlen <ccarlen@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcMessageReader_h__
+#define ipcMessageReader_h__
+
+#include "prtypes.h"
+
+//*****************************************************************************
+// ipcMessageReader
+//
+// Reads from a const buffer supplied to it. Does not take ownership of the
+// buffer. Bytes are read in native endianess, as ipcMessageWriter writes them
+// in native endianess.
+//*****************************************************************************
+
+class ipcMessageReader
+{
+public:
+ ipcMessageReader(const PRUint8* inBuffer, PRUint32 bufferSize) :
+ mBuf(inBuffer), mBufEnd(inBuffer + bufferSize),
+ mBufPtr(mBuf),
+ mError(PR_FALSE)
+ { }
+
+ ~ipcMessageReader()
+ { }
+
+ // Returns PR_TRUE if an error has occured at any point
+ // during the lifetime of this object. Any read operation
+ // will safely return 0 on an error condition.
+ PRBool HasError()
+ { return mError; }
+
+ PRUint8 GetInt8();
+ PRUint16 GetInt16();
+ PRUint32 GetInt32();
+ PRInt32 GetBytes(void* destBuffer, PRInt32 n);
+
+ // Returns data at the current read position.
+ const PRUint8* GetPtr()
+ { return mBufPtr; }
+
+ // Returns PR_TRUE if the new position is within the buffer.
+ // Returns PR_FALSE and sets error state if not.
+ PRBool AdvancePtr(PRInt32 n);
+
+private:
+ const PRUint8 *mBuf, *mBufEnd;
+ const PRUint8 *mBufPtr;
+ PRBool mError;
+};
+
+#endif // ipcMessageReader_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageWriter.h b/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageWriter.h
new file mode 100644
index 00000000..8e0a8178
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageWriter.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Conrad Carlen <ccarlen@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef ipcMessageWriter_h__
+#define ipcMessageWriter_h__
+
+#include "prtypes.h"
+
+//*****************************************************************************
+// ipcMessageWriter
+//
+// Creates a block of memory and resizes it in order to hold writes. The
+// block will be freed when this object is destroyed. Bytes are written in
+// native endianess, as ipcMessageReader reads them in native endianess.
+//*****************************************************************************
+
+class ipcMessageWriter
+{
+public:
+ ipcMessageWriter(PRUint32 initialCapacity) :
+ mBuf(NULL),
+ mBufPtr(NULL), mBufEnd(NULL),
+ mCapacity(0),
+ mError(PR_FALSE)
+ {
+ EnsureCapacity(initialCapacity);
+ }
+
+ ~ipcMessageWriter();
+
+ // Returns PR_TRUE if an error has occured at any point
+ // during the lifetime of this object, due to the buffer
+ // not being able to be grown to the required size.
+ PRBool HasError()
+ { return mError; }
+
+ void PutInt8(PRUint8 val);
+ void PutInt16(PRUint16 val);
+ void PutInt32(PRUint32 val);
+ PRUint32 PutBytes(const void* src, PRUint32 n);
+
+ // Returns the beginning of the buffer. Do not free this.
+ PRUint8* GetBuffer()
+ { return mBuf; }
+
+ PRInt32 GetSize()
+ { return mBufPtr - mBuf; }
+
+private:
+ PRBool EnsureCapacity(PRInt32 sizeNeeded)
+ {
+ return (mBuf && ((mBufPtr + sizeNeeded) <= mBufEnd)) ?
+ PR_TRUE : GrowCapacity(sizeNeeded);
+ }
+ PRBool GrowCapacity(PRInt32 sizeNeeded);
+
+private:
+ PRUint8 *mBuf;
+ PRUint8 *mBufPtr, *mBufEnd;
+ PRInt32 mCapacity;
+ PRBool mError;
+};
+
+#endif // ipcMessageWriter_h__
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in
new file mode 100644
index 00000000..6ebca736
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in
@@ -0,0 +1,56 @@
+# vim: noexpandtab ts=4 sw=4
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla IPC.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2003
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Conrad Carlen <ccarlen@netscape.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = ipcd
+LIBRARY_NAME = ipcdutil_s
+FORCE_STATIC_LIB = 1
+MODULE_NAME = ipcd
+
+
+CPPSRCS = \
+ ipcMessageReader.cpp \
+ ipcMessageWriter.cpp
+
+include $(topsrcdir)/config/rules.mk
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageReader.cpp b/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageReader.cpp
new file mode 100644
index 00000000..87279df2
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageReader.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Conrad Carlen <ccarlen@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcMessageReader.h"
+#include <string.h>
+
+//*****************************************************************************
+// ipcMessageReader
+//*****************************************************************************
+
+PRUint8 ipcMessageReader::GetInt8()
+{
+ if (mBufPtr < mBufEnd)
+ return *mBufPtr++;
+ mError = PR_TRUE;
+ return 0;
+}
+
+// GetInt16 and GetInt32 go to pains to avoid unaligned memory accesses that
+// are larger than a byte. On some platforms, that causes a performance penalty.
+// On other platforms, Tru64 for instance, it's an error.
+
+PRUint16 ipcMessageReader::GetInt16()
+{
+ if (mBufPtr + sizeof(PRUint16) <= mBufEnd) {
+ PRUint8 temp[2] = { mBufPtr[0], mBufPtr[1] };
+ mBufPtr += sizeof(PRUint16);
+ return *(PRUint16*)temp;
+ }
+ mError = PR_TRUE;
+ return 0;
+}
+
+PRUint32 ipcMessageReader::GetInt32()
+{
+ if (mBufPtr + sizeof(PRUint32) <= mBufEnd) {
+ PRUint8 temp[4] = { mBufPtr[0], mBufPtr[1], mBufPtr[2], mBufPtr[3] };
+ mBufPtr += sizeof(PRUint32);
+ return *(PRUint32*)temp;
+ }
+ mError = PR_TRUE;
+ return 0;
+}
+
+PRInt32 ipcMessageReader::GetBytes(void* destBuffer, PRInt32 n)
+{
+ if (mBufPtr + n <= mBufEnd) {
+ memcpy(destBuffer, mBufPtr, n);
+ mBufPtr += n;
+ return n;
+ }
+ mError = PR_TRUE;
+ return 0;
+}
+
+PRBool ipcMessageReader::AdvancePtr(PRInt32 n)
+{
+ const PRUint8 *newPtr = mBufPtr + n;
+ if (newPtr >= mBuf && newPtr <= mBufEnd) {
+ mBufPtr = newPtr;
+ return PR_TRUE;
+ }
+ mError = PR_TRUE;
+ return PR_FALSE;
+}
diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageWriter.cpp b/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageWriter.cpp
new file mode 100644
index 00000000..4af0dcba
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageWriter.cpp
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla IPC.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Conrad Carlen <ccarlen@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "ipcMessageWriter.h"
+#include "prmem.h"
+#include <string.h>
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+# include <iprt/mem.h>
+#endif
+
+//*****************************************************************************
+// ipcMessageWriter
+//*****************************************************************************
+
+ipcMessageWriter::~ipcMessageWriter()
+{
+ if (mBuf)
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ RTMemFree(mBuf);
+#else
+ free(mBuf);
+#endif
+}
+
+void ipcMessageWriter::PutInt8(PRUint8 val)
+{
+ if (EnsureCapacity(sizeof(PRUint8)))
+ *mBufPtr++ = val;
+}
+
+// PutInt16 and PutInt32 go to pains to avoid unaligned memory accesses that
+// are larger than a byte. On some platforms, that causes a performance penalty.
+// On other platforms, Tru64 for instance, it's an error.
+
+void ipcMessageWriter::PutInt16(PRUint16 val)
+{
+ if (EnsureCapacity(sizeof(PRUint16))) {
+ PRUint8 temp[2];
+ *(PRUint16*)temp = val;
+ *mBufPtr++ = temp[0];
+ *mBufPtr++ = temp[1];
+ }
+}
+
+void ipcMessageWriter::PutInt32(PRUint32 val)
+{
+ if (EnsureCapacity(sizeof(PRUint32))) {
+ PRUint8 temp[4];
+ *(PRUint32*)temp = val;
+ *mBufPtr++ = temp[0];
+ *mBufPtr++ = temp[1];
+ *mBufPtr++ = temp[2];
+ *mBufPtr++ = temp[3];
+ }
+}
+
+PRUint32 ipcMessageWriter::PutBytes(const void* src, PRUint32 n)
+{
+ if (EnsureCapacity(n)) {
+ memcpy(mBufPtr, src, n);
+ mBufPtr += n;
+ return n;
+ }
+ return 0;
+}
+
+PRBool ipcMessageWriter::GrowCapacity(PRInt32 sizeNeeded)
+{
+ if (sizeNeeded < 0)
+ return PR_FALSE;
+ PRInt32 newCapacity = (mBufPtr - mBuf) + sizeNeeded;
+ if (mCapacity == 0)
+ mCapacity = newCapacity;
+ else
+ {
+ while (newCapacity > mCapacity && (mCapacity << 1) > 0)
+ mCapacity <<= 1;
+ if (newCapacity > mCapacity) // if we broke out because of rollover
+ return PR_FALSE;
+ }
+
+ PRInt32 curPos = mBufPtr - mBuf;
+#ifdef VBOX_USE_IPRT_IN_XPCOM
+ mBuf = (PRUint8*)RTMemRealloc(mBuf, mCapacity);
+#else
+ mBuf = (PRUint8*)realloc(mBuf, mCapacity);
+#endif
+ if (!mBuf) {
+ mError = PR_TRUE;
+ return PR_FALSE;
+ }
+ mBufPtr = mBuf + curPos;
+ mBufEnd = mBuf + mCapacity;
+ return PR_TRUE;
+}