summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/ipc/ipcd/extensions
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
commitf8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch)
tree26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/libs/xpcom18a4/ipc/ipcd/extensions
parentInitial commit. (diff)
downloadvirtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz
virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libs/xpcom18a4/ipc/ipcd/extensions')
-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.cpp4217
-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
64 files changed, 10545 insertions, 0 deletions
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..db36313b
--- /dev/null
+++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp
@@ -0,0 +1,4217 @@
+/* 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:
+ {
+ if (v.val.p)
+ writer.PutBytes(v.val.p, sizeof(nsID));
+ else
+ return NS_ERROR_INVALID_POINTER;
+ }
+ 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);
+ 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)
+{
+ if (!aMessage)
+ return NS_ERROR_INVALID_POINTER;
+ *aMessage = ToNewCString(mMessage);
+ return NS_OK;
+}
+
+/* readonly attribute nsresult result; */
+NS_IMETHODIMP ExceptionStub::GetResult(nsresult *aResult)
+{
+ if (!aResult)
+ return NS_ERROR_INVALID_POINTER;
+ *aResult = mResult;
+ return NS_OK;
+}
+
+/* readonly attribute string name; */
+NS_IMETHODIMP ExceptionStub::GetName(char **aName)
+{
+ if (!aName)
+ return NS_ERROR_INVALID_POINTER;
+ *aName = ToNewCString(mName);
+ return NS_OK;
+}
+
+/* readonly attribute string filename; */
+NS_IMETHODIMP ExceptionStub::GetFilename(char **aFilename)
+{
+ if (!aFilename)
+ return NS_ERROR_INVALID_POINTER;
+ *aFilename = ToNewCString(mFilename);
+ return NS_OK;
+}
+
+/* readonly attribute PRUint32 lineNumber; */
+NS_IMETHODIMP ExceptionStub::GetLineNumber(PRUint32 *aLineNumber)
+{
+ if (!aLineNumber)
+ return NS_ERROR_INVALID_POINTER;
+ *aLineNumber = mLineNumber;
+ return NS_OK;
+}
+
+/* readonly attribute PRUint32 columnNumber; */
+NS_IMETHODIMP ExceptionStub::GetColumnNumber(PRUint32 *aColumnNumber)
+{
+ if (!aColumnNumber)
+ return 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]);
+
+ if (NS_FAILED(rv))
+ break;
+ }
+ 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;
+ 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;
+}