From 439c8ef2b1e6311024cbca26df86f0de2d2dba2b Mon Sep 17 00:00:00 2001 From: "darin%meer.net" Date: Mon, 3 May 2004 18:40:33 +0000 Subject: [PATCH] patch for bug 242248 "IPC synchronous message support needs to be reworked" (not yet used for anything) git-svn-id: svn://10.0.0.236/trunk@155858 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/ipc/ipcd/client/public/Makefile.in | 7 +- .../ipcd/client/public/ipcIClientObserver.idl | 4 +- .../client/public/ipcIMessageObserver.idl | 6 +- .../ipc/ipcd/client/public/ipcIService.idl | 135 +- mozilla/ipc/ipcd/client/public/ipcdclient.h | 228 ++++ mozilla/ipc/ipcd/client/src/Makefile.in | 2 +- mozilla/ipc/ipcd/client/src/ipcConnection.h | 15 +- .../ipc/ipcd/client/src/ipcModuleFactory.cpp | 47 + mozilla/ipc/ipcd/client/src/ipcService.cpp | 456 +------ mozilla/ipc/ipcd/client/src/ipcService.h | 41 +- mozilla/ipc/ipcd/client/src/ipcTransport.cpp | 2 +- mozilla/ipc/ipcd/client/src/ipcdclient.cpp | 1129 +++++++++++++++++ .../ipc/ipcd/daemon/src/ipcCommandModule.cpp | 71 +- mozilla/ipc/ipcd/daemon/src/ipcModuleReg.cpp | 4 +- mozilla/ipc/ipcd/daemon/src/ipcModuleReg.h | 4 +- mozilla/ipc/ipcd/daemon/src/ipcd.cpp | 28 + mozilla/ipc/ipcd/daemon/src/ipcd.h | 6 + .../ipcd/extensions/lock/public/Makefile.in | 4 + .../lock/public/ipcILockService.idl | 15 - .../extensions/lock/src/ipcLockProtocol.h | 3 +- .../extensions/lock/src/ipcLockService.cpp | 46 +- .../ipcd/extensions/lock/src/ipcLockService.h | 21 +- .../lock/src/module/ipcLockModule.cpp | 100 +- .../transmngr/src/tmTransactionService.cpp | 32 +- .../transmngr/src/tmTransactionService.h | 3 +- mozilla/ipc/ipcd/shared/src/ipcConfig.h | 4 +- mozilla/ipc/ipcd/shared/src/ipcIDList.h | 4 +- mozilla/ipc/ipcd/shared/src/ipcList.h | 11 + mozilla/ipc/ipcd/shared/src/ipcLog.h | 5 +- mozilla/ipc/ipcd/shared/src/ipcMessage.h | 39 +- .../ipcd/shared/src/ipcMessagePrimitives.cpp | 35 +- .../ipcd/shared/src/ipcMessagePrimitives.h | 101 +- mozilla/ipc/ipcd/shared/src/ipcStringList.h | 6 +- mozilla/ipc/ipcd/shared/src/ipcm.cpp | 58 +- mozilla/ipc/ipcd/shared/src/ipcm.h | 635 +++++---- mozilla/ipc/ipcd/test/TestIPC.cpp | 51 +- 36 files changed, 2382 insertions(+), 976 deletions(-) create mode 100644 mozilla/ipc/ipcd/client/public/ipcdclient.h create mode 100644 mozilla/ipc/ipcd/client/src/ipcdclient.cpp diff --git a/mozilla/ipc/ipcd/client/public/Makefile.in b/mozilla/ipc/ipcd/client/public/Makefile.in index b430c9b0fc9..ca870e10361 100644 --- a/mozilla/ipc/ipcd/client/public/Makefile.in +++ b/mozilla/ipc/ipcd/client/public/Makefile.in @@ -45,11 +45,16 @@ include $(DEPTH)/config/autoconf.mk MODULE = ipcd +EXPORTS = \ + ipcdclient.h \ + ipcCID.h \ + $(NULL) + XPIDLSRCS = \ ipcIService.idl \ ipcIMessageObserver.idl \ ipcIClientObserver.idl \ - ipcIClientQueryHandler.idl \ + ipcIClientInfo.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/mozilla/ipc/ipcd/client/public/ipcIClientObserver.idl b/mozilla/ipc/ipcd/client/public/ipcIClientObserver.idl index 91290fa52e5..c72d090963c 100644 --- a/mozilla/ipc/ipcd/client/public/ipcIClientObserver.idl +++ b/mozilla/ipc/ipcd/client/public/ipcIClientObserver.idl @@ -46,6 +46,6 @@ interface ipcIClientObserver : nsISupports const unsigned long CLIENT_UP = 1; const unsigned long CLIENT_DOWN = 2; - void onClientStatus(in unsigned long aClientID, - in unsigned long aClientStatus); + void onClientStateChange(in unsigned long aClientID, + in unsigned long aClientState); }; diff --git a/mozilla/ipc/ipcd/client/public/ipcIMessageObserver.idl b/mozilla/ipc/ipcd/client/public/ipcIMessageObserver.idl index 0e46c6b4cd0..db24b1f2690 100644 --- a/mozilla/ipc/ipcd/client/public/ipcIMessageObserver.idl +++ b/mozilla/ipc/ipcd/client/public/ipcIMessageObserver.idl @@ -44,6 +44,9 @@ interface ipcIMessageObserver : nsISupports { /** + * @param aSenderID + * the client id of the sender of this message. if sent by the + * daemon (or a deamon module), then this will have a value of 0. * @param aTarget * the target of the message, corresponding to the target this * observer was registered under. this parameter is passed to allow @@ -53,7 +56,8 @@ interface ipcIMessageObserver : nsISupports * @param aDataLen * the data length of the message. */ - void onMessageAvailable(in nsIDRef aTarget, + void onMessageAvailable(in unsigned long aSenderID, + in nsIDRef aTarget, [array, const, size_is(aDataLen)] in octet aData, in unsigned long aDataLen); diff --git a/mozilla/ipc/ipcd/client/public/ipcIService.idl b/mozilla/ipc/ipcd/client/public/ipcIService.idl index 91caf3ad900..b3c0d4d5220 100644 --- a/mozilla/ipc/ipcd/client/public/ipcIService.idl +++ b/mozilla/ipc/ipcd/client/public/ipcIService.idl @@ -39,7 +39,6 @@ interface ipcIMessageObserver; interface ipcIClientObserver; -interface ipcIClientQueryHandler; /** * ipcIService @@ -82,7 +81,7 @@ interface ipcIService : nsISupports * * @throws NS_ERROR_NOT_AVAILABLE if no connection to the IPC daemon. */ - readonly attribute unsigned long clientID; + readonly attribute unsigned long ID; /** * this process can appear under several client names. use the following @@ -95,71 +94,42 @@ interface ipcIService : nsISupports * * XXX An IPC client name resembles a XPCOM contract ID. */ - void addClientName(in string aName); - void removeClientName(in string aName); + void addName(in string aName); + void removeName(in string aName); + /** + * add a new observer of client status change notifications. + */ + void addClientObserver(in ipcIClientObserver aObserver); + + /** + * remove an observer of client status change notifications. + */ + void removeClientObserver(in ipcIClientObserver aObserver); /************************************************************************** * client query methods */ /** - * query info about a particular client given its client name. the - * observer's onClientInfo method is called with the result of the lookup, - * or if there is no client matching the given name, the observer's - * onClientDown method will be called instead. - * - * @param aName - * the name of the client being queried. - * @param aHandler - * the handler to be notified with result. - * @param aSync - * block the calling thread until the query completes. - * - * @return integer value identifying this query. + * resolve the given client name to the id of a connected client. this + * involves a round trip to the daemon, and as a result the calling thread + * may block on this function call while waiting for the daemon to respond. */ - unsigned long queryClientByName(in string aName, - in ipcIClientQueryHandler aHandler, - in boolean aSync); + unsigned long resolveClientName(in string aName); + /** - * query info about a particular client given its client ID. the observer's - * onClientInfo method is called with the result of the lookup, or if there - * is no client matching the given name, the observer's onClientDown method - * will be called instead. - * - * @param aClientID - * the ID of the client being queried. - * @param aHandler - * the handler to be notified with result. - * @param aSync - * block the calling thread until the query completes. - * - * @return integer value identifying this query. + * tests whether a particular client is connected to the IPC daemon. */ - unsigned long queryClientByID(in unsigned long aClientID, - in ipcIClientQueryHandler aHandler, - in boolean aSync); + boolean clientExists(in unsigned long aClientID); - /** - * called to cancel a pending query. - * - * @param aQueryID - * the return value from one of the "query" methods. - */ - void cancelQuery(in unsigned long aQueryID); - - /** - * set client observer. observer's onClientUp method is called whenever - * a new client comes online, and the observer's onClientDown method is - * called whenever a client goes offline. - * - * @param aObserver - * the client observer. - */ - void setClientObserver(in ipcIClientObserver aObserver); // XXX need other functions to enumerate clients, clients implementing targets, etc. + // enumerator getClients(); + // enumerator getClientsSupportingTarget(in nsIDRef aTarget); + // enumerator getClientNames(in unsigned long aClientID); + // enumerator getClientTargets(in unsigned long aClientID); /************************************************************************** @@ -176,7 +146,7 @@ interface ipcIService : nsISupports * the message observer to receive incoming messages for the * specified target. pass null to remove the existing observer. */ - void setMessageObserver(in nsIDRef aTarget, in ipcIMessageObserver aObserver); + void defineTarget(in nsIDRef aTarget, in ipcIMessageObserver aObserver); /** * send message asynchronously to a client or a module in the IPC daemon. @@ -192,33 +162,50 @@ interface ipcIService : nsISupports * the message data. * @param aDataLen * the message length. - * @param aSync - * block the calling thread until a response to this message is - * received. */ - void sendMessage(in unsigned long aClientID, + void sendMessage(in unsigned long aReceiverID, in nsIDRef aTarget, [array, const, size_is(aDataLen)] in octet aData, - in unsigned long aDataLen, - in boolean aSync); + in unsigned long aDataLen); + + /** + * block the calling thread until a matching message is received. + * + * @param aSenderID + * pass 0 to wait for a message from the daemon. pass PR_UINT32_MAX + * to wait for a message from any source. otherwise, pass a client + * id to wait for a message from that particular client. + * @param aTarget + * wait for a message to be delivered to this target. + * @param aObserver + * this observer's OnMessageAvailable method is called when a + * matching message is available. pass null to use the default + * observer associated with aTarget. + * @param aTimeout + * indicates maximum length of time in milliseconds that this + * function may block the calling thread. + * + * @throws IPC_ERROR_WOULD_BLOCK if the timeout expires. + * + * the observer's OnMessageAvailable method may throw IPC_WAIT_NEXT_MESSAGE + * to indicate that it does not wish to handle the message that it was + * given, and that it will wait to be called with the next message. this + * enables the observer to keep messages in the queue that do not match the + * desired message. messages that remain in the queue will be dispatched + * asynchronously to the default message handler after waitMessage finishes. + * + * NOTE: this function may hang the calling thread until a matching message + * is received, so use it with caution. + */ + void waitMessage(in unsigned long aSenderID, + in nsIDRef aTarget, + in ipcIMessageObserver aObserver, + in unsigned long aTimeout); }; %{C++ -// singleton implementing ipcIService -#define IPC_SERVICE_CLASSNAME \ - "ipcService" -#define IPC_SERVICE_CONTRACTID \ - "@mozilla.org/ipc/service;1" -#define IPC_SERVICE_CID \ -{ /* 9f12676a-5168-4a08-beb8-edf8a593a1ca */ \ - 0x9f12676a, \ - 0x5168, \ - 0x4a08, \ - {0xbe, 0xb8, 0xed, 0xf8, 0xa5, 0x93, 0xa1, 0xca} \ -} - -// category and observer event defines +// category and observer event defines (XXX not yet implemented) #define IPC_SERVICE_STARTUP_CATEGORY "ipc-startup-category" #define IPC_SERVICE_STARTUP_TOPIC "ipc-startup" #define IPC_SERVICE_SHUTDOWN_TOPIC "ipc-shutdown" diff --git a/mozilla/ipc/ipcd/client/public/ipcdclient.h b/mozilla/ipc/ipcd/client/public/ipcdclient.h new file mode 100644 index 00000000000..2f179f974ae --- /dev/null +++ b/mozilla/ipc/ipcd/client/public/ipcdclient.h @@ -0,0 +1,228 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef ipcdclient_h__ +#define ipcdclient_h__ + +/***************************************************************************** + * This file provides a client-side API to the IPC daemon. + * + * This API can be used to communicate with other clients of the IPC daemon + * as well as modules running inside the IPC daemon. + * + * This API is meant to be used only on the application's main thread. It is + * assumed that callbacks can be dispatched via the main thread's event queue. + */ + +#include "nscore.h" +#include "nsID.h" +#include "nsError.h" +#include "ipcIMessageObserver.h" +#include "ipcIClientObserver.h" + +/* This API is only provided for the extensions compiled into the IPCDC + * library, hence this API is hidden in the final DSO. */ +#define IPC_METHOD NS_HIDDEN_(nsresult) + +/* This value can be used to represent the client id of any client connected + * to the IPC daemon. */ +#define IPC_SENDER_ANY PR_UINT32_MAX + +/* This error code can only be returned by OnMessageAvailable, when called by + * IPC_WaitMessage. See IPC_WaitMessage for a description of how this error + * code may be used. */ +#define IPC_WAIT_NEXT_MESSAGE \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 10) + +/* This error code is returned by IPC_WaitMessage under certain conditions. */ +#define IPC_ERROR_WOULD_BLOCK NS_BASE_STREAM_WOULD_BLOCK + +/***************************************************************************** + * Initialization and Shutdown + */ + +/** + * Ensures that this process is connected to the IPC daemon. If it is already + * connected, then this function call has no effect. Each call to IPC_Init + * should be balanced by a call to IPC_Shutdown. A reference counter is used + * to determine when to disconnect from the IPC daemon. + */ +IPC_METHOD IPC_Init(); + +/** + * Disconnects this process from the IPC daemon. Must be called once for + * every call to IPC_Init when the IPC connection is no longer needed. + */ +IPC_METHOD IPC_Shutdown(); + + +/***************************************************************************** + * The core messaging API + */ + +/** + * Call this method to define a message target. A message target is defined + * by a UUID and a message observer. This observer is notified asynchronously + * whenever a message is sent to this target in this process. + * + * This function has three main effects: + * o If the message target is already defined, then this function simply resets + * its message observer. + * o If the message target is not already defined, then the IPC daemon will be + * notified of the existance of this message target. + * o If null is passed for the message observer, then the message target is + * removed, and the daemon is notified of the removal of this message target. + */ +IPC_METHOD IPC_DefineTarget( + const nsID &aTarget, + ipcIMessageObserver *aObserver +); + +/** + * This function sends a message to the IPC daemon asynchronously. If + * aReceiverID is non-zero, then the message is forwarded to the client + * corresponding to that identifier. + * + * If there is no client corresponding to aRecieverID, then the IPC daemon will + * simply drop the message. + */ +IPC_METHOD IPC_SendMessage( + PRUint32 aReceiverID, + const nsID &aTarget, + const PRUint8 *aData, + PRUint32 aDataLen +); + +/** + * This function blocks the calling thread until a message for the given target + * is received (optionally from the specified client). + * + * The aSenderID parameter is interpreted as follows: + * o If aSenderID is 0, then this function waits for a message to be sent by + * the IPC daemon. + * o If aSenderID is IPC_SENDER_ANY, then this function waits for a message + * to be sent from any source. + * o Otherwise, this function waits for a message to be sent by client with + * ID given by aSenderID. If aSenderID does not identify a valid client, + * then this function will return an error. + * + * The aObserver parameter is interpreted as follows: + * o If aObserver is null, then the default message observer for the target + * is invoked when the next message is received. + * o Otherwise, aObserver will be inovked when the next message is received. + * + * The aTimeout parameter is interpreted as follows: + * o If aTimeout is PR_INTERVAL_NO_TIMEOUT, then this function will block + * until a matching message is received. + * o If aTimeout is PR_INTERVAL_NO_WAIT, then this function will only inspect + * the current queue of messages. If no matching message is found, then + * IPC_ERROR_WOULD_BLOCK is returned. + * o Otherwise, aTimeout specifies the maximum amount of time to wait for a + * matching message to be received. If no matching message is found after + * the timeout expires, then IPC_ERROR_WOULD_BLOCK is returned. + * + * If aObserver's OnMessageAvailable function returns IPC_WAIT_NEXT_MESSAGE, + * then the function will continue blocking until the next matching message + * is received. Bypassed messages will be dispatched to the default message + * observer when the thread's event queue is processed. + * + * This function runs the risk of hanging the calling thread indefinitely if + * no matching message is ever received. + */ +IPC_METHOD IPC_WaitMessage( + PRUint32 aSenderID, + const nsID &aTarget, + ipcIMessageObserver *aObserver = nsnull, + PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT +); + +/*****************************************************************************/ + +/** + * Returns the "ClientID" of the current process. + */ +IPC_METHOD IPC_GetID( + PRUint32 *aClientID +); + +/** + * Adds a new name for the current process. The IPC daemon is notified of this + * change, which allows other processes to discover this process by the given + * name. + */ +IPC_METHOD IPC_AddName( + const char *aName +); + +/** + * Removes a name associated with the current process. + */ +IPC_METHOD IPC_RemoveName( + const char *aName +); + +/** + * Adds client observer. + */ +IPC_METHOD IPC_AddClientObserver( + ipcIClientObserver *aObserver +); + +/** + * Removes client observer. + */ +IPC_METHOD IPC_RemoveClientObserver( + ipcIClientObserver *aObserver +); + +/** + * Resolves the given client name to a client ID of a process connected to + * the IPC daemon. + */ +IPC_METHOD IPC_ResolveClientName( + const char *aName, + PRUint32 *aClientID +); + +/** + * Tests whether the client is connected to the IPC daemon. + */ +IPC_METHOD IPC_ClientExists( + PRUint32 aClientID, + PRBool *aResult +); + +#endif /* ipcdclient_h__ */ diff --git a/mozilla/ipc/ipcd/client/src/Makefile.in b/mozilla/ipc/ipcd/client/src/Makefile.in index b410455257a..bccc586fd06 100644 --- a/mozilla/ipc/ipcd/client/src/Makefile.in +++ b/mozilla/ipc/ipcd/client/src/Makefile.in @@ -55,8 +55,8 @@ REQUIRES = \ $(NULL) CPPSRCS = \ + ipcdclient.cpp \ ipcService.cpp \ - ipcTransport.cpp \ ipcModuleFactory.cpp \ $(NULL) diff --git a/mozilla/ipc/ipcd/client/src/ipcConnection.h b/mozilla/ipc/ipcd/client/src/ipcConnection.h index 594b29ddf03..d80027c775d 100644 --- a/mozilla/ipc/ipcd/client/src/ipcConnection.h +++ b/mozilla/ipc/ipcd/client/src/ipcConnection.h @@ -42,6 +42,9 @@ class ipcMessage; +#define IPC_METHOD_PRIVATE_(type) NS_HIDDEN_(type) +#define IPC_METHOD_PRIVATE IPC_METHOD_PRIVATE_(nsresult) + /* ------------------------------------------------------------------------- */ /* Platform specific IPC connection API. */ @@ -57,7 +60,7 @@ class ipcMessage; * * NOTE: This function must be called on the main thread. */ -nsresult IPC_Connect(const char *daemonPath); +IPC_METHOD_PRIVATE IPC_Connect(const char *daemonPath); /** * IPC_Disconnect @@ -68,7 +71,7 @@ nsresult IPC_Connect(const char *daemonPath); * * NOTE: This function must be called on the main thread. */ -nsresult IPC_Disconnect(); +IPC_METHOD_PRIVATE IPC_Disconnect(); /** * IPC_SendMsg @@ -82,7 +85,7 @@ nsresult IPC_Disconnect(); * * NOTE: This function may be called on any thread. */ -nsresult IPC_SendMsg(ipcMessage *msg); +IPC_METHOD_PRIVATE IPC_SendMsg(ipcMessage *msg); /* ------------------------------------------------------------------------- */ /* Cross-platform IPC connection methods. @@ -99,7 +102,7 @@ nsresult IPC_SendMsg(ipcMessage *msg); * @param daemonPath * Specifies the path to the IPC daemon executable. */ -nsresult IPC_SpawnDaemon(const char *daemonPath); +IPC_METHOD_PRIVATE IPC_SpawnDaemon(const char *daemonPath); /* ------------------------------------------------------------------------- */ /* IPC connection callbacks (not implemented by the connection code). @@ -115,7 +118,7 @@ nsresult IPC_SpawnDaemon(const char *daemonPath); * described by the |error| parameter. If |error| is NS_OK, then it means the * connection was closed in response to a call to IPC_Disconnect. */ -void IPC_OnConnectionEnd(nsresult error); +IPC_METHOD_PRIVATE_(void) IPC_OnConnectionEnd(nsresult error); /** * IPC_OnMessageAvailable @@ -124,6 +127,6 @@ void IPC_OnConnectionEnd(nsresult error); * daemon. The ipcMessage object, |msg|, must be deleted by the implementation * of IPC_OnMessageAvailable when the object is no longer needed. */ -void IPC_OnMessageAvailable(ipcMessage *msg); +IPC_METHOD_PRIVATE_(void) IPC_OnMessageAvailable(ipcMessage *msg); #endif // ipcConnection_h__ diff --git a/mozilla/ipc/ipcd/client/src/ipcModuleFactory.cpp b/mozilla/ipc/ipcd/client/src/ipcModuleFactory.cpp index 96805a93a19..72c27a30674 100644 --- a/mozilla/ipc/ipcd/client/src/ipcModuleFactory.cpp +++ b/mozilla/ipc/ipcd/client/src/ipcModuleFactory.cpp @@ -40,6 +40,8 @@ #include "nsICategoryManager.h" #include "ipcService.h" #include "ipcConfig.h" +#include "ipcCID.h" +#include "ipcLockCID.h" //----------------------------------------------------------------------------- // Define the contructor function for the objects @@ -93,6 +95,45 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcLockService, Init) #include "tmTransactionService.h" NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService) +#if 0 +#include "ipcDConnectService.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcDConnectService, Init) + +// enable this code to make the IPC DCONNECT service auto-start. +NS_METHOD +ipcDConnectServiceRegisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + // + // add ipcService to the XPCOM startup category + // + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) { + nsXPIDLCString prevEntry; + catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcDConnectService", + IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE, PR_TRUE, + getter_Copies(prevEntry)); + } + return NS_OK; +} + +NS_METHOD +ipcDConnectServiceUnregisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const nsModuleComponentInfo *info) +{ + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) + catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, + IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE); + return NS_OK; +} +#endif + //----------------------------------------------------------------------------- // Define a table of CIDs implemented by this module along with other // information like the function to create an instance, contractid, and @@ -118,6 +159,12 @@ static const nsModuleComponentInfo components[] = { IPC_TRANSACTIONSERVICE_CID, IPC_TRANSACTIONSERVICE_CONTRACTID, tmTransactionServiceConstructor }, +#if 0 + { IPC_DCONNECTSERVICE_CLASSNAME, + IPC_DCONNECTSERVICE_CID, + IPC_DCONNECTSERVICE_CONTRACTID, + ipcDConnectServiceConstructor }, +#endif }; //----------------------------------------------------------------------------- diff --git a/mozilla/ipc/ipcd/client/src/ipcService.cpp b/mozilla/ipc/ipcd/client/src/ipcService.cpp index 10287a64f6d..d01a7118640 100644 --- a/mozilla/ipc/ipcd/client/src/ipcService.cpp +++ b/mozilla/ipc/ipcd/client/src/ipcService.cpp @@ -14,9 +14,8 @@ * * 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 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): @@ -36,472 +35,69 @@ * * ***** END LICENSE BLOCK ***** */ -#include - -#include "plstr.h" - -#include "nsIServiceManager.h" -#include "nsIEventQueueService.h" -#include "nsIEventQueue.h" -#include "nsIObserverService.h" -#include "nsICategoryManager.h" -#include "nsCategoryManagerUtils.h" -#include "nsEventQueueUtils.h" - -#include "ipcConfig.h" -#include "ipcLog.h" #include "ipcService.h" -#include "ipcMessageUtils.h" -#include "ipcm.h" -#include "ipcIMessageObserver.h" -#include "ipcIClientObserver.h" -#include "ipcIClientQueryHandler.h" - -//----------------------------------------------------------------------------- -// helpers -//----------------------------------------------------------------------------- - -static PRBool PR_CALLBACK -ipcReleaseMessageObserver(nsHashKey *aKey, void *aData, void* aClosure) -{ - ipcIMessageObserver *obs = (ipcIMessageObserver *) aData; - NS_RELEASE(obs); - return PR_TRUE; -} - -//---------------------------------------------------------------------------- -// ipcClientQuery -//---------------------------------------------------------------------------- - -class ipcClientQuery -{ -public: - ipcClientQuery(PRUint32 cID, ipcIClientQueryHandler *handler) - : mNext(nsnull) - , mQueryID(++gLastQueryID) - , mClientID(cID) - , mHandler(handler) - { } - - static PRUint32 gLastQueryID; - - void SetClientID(PRUint32 cID) { mClientID = cID; } - void OnQueryComplete(nsresult status, const ipcmMessageClientInfo *msg); - - PRUint32 QueryID() { return mQueryID; } - PRBool IsCanceled() { return mHandler.get() == NULL; } - - ipcClientQuery *mNext; -private: - PRUint32 mQueryID; - PRUint32 mClientID; - nsCOMPtr mHandler; -}; - -PRUint32 ipcClientQuery::gLastQueryID = 0; - -void -ipcClientQuery::OnQueryComplete(nsresult status, const ipcmMessageClientInfo *msg) -{ - NS_ASSERTION(mHandler, "no handler"); - - PRUint32 nameCount = 0; - PRUint32 targetCount = 0; - const char **names = NULL; - const nsID **targets = NULL; - - if (NS_SUCCEEDED(status)) { - nameCount = msg->NameCount(); - targetCount = msg->TargetCount(); - PRUint32 i; - - names = (const char **) malloc(nameCount * sizeof(char *)); - const char *lastName = NULL; - for (i = 0; i < nameCount; ++i) { - lastName = msg->NextName(lastName); - names[i] = lastName; - } - - targets = (const nsID **) malloc(targetCount * sizeof(nsID *)); - const nsID *lastTarget = NULL; - for (i = 0; i < targetCount; ++i) { - lastTarget = msg->NextTarget(lastTarget); - targets[i] = lastTarget; - } - } - - mHandler->OnQueryComplete(mQueryID, - status, - mClientID, - names, nameCount, - targets, targetCount); - mHandler = NULL; - - if (names) - free(names); - if (targets) - free(targets); -} - -//----------------------------------------------------------------------------- -// ipcService -//----------------------------------------------------------------------------- - -ipcService::ipcService() - : mTransport(nsnull) - , mClientID(0) -{ - IPC_InitLog(">>>"); -} - -ipcService::~ipcService() -{ - NS_ASSERTION(mTransport == nsnull, "no xpcom-shutdown event??"); -} - -nsresult -ipcService::Init() -{ - nsCOMPtr observ(do_GetService("@mozilla.org/observer-service;1")); - if (observ) - observ->AddObserver(this, "xpcom-shutdown", PR_FALSE); - - nsresult rv; - mTransport = new ipcTransport(); - if (!mTransport) - rv = NS_ERROR_OUT_OF_MEMORY; - else { - rv = mTransport->Init(this, &mClientID); - if (NS_FAILED(rv)) - mTransport = nsnull; - else { - // - // broadcast IPC startup... - // - NS_CreateServicesFromCategory(IPC_SERVICE_STARTUP_CATEGORY, - NS_STATIC_CAST(ipcIService *, this), - IPC_SERVICE_STARTUP_TOPIC); - } - } - return rv; -} - -void -ipcService::Shutdown() -{ - // - // broadcast IPC shutdown... - // - nsCOMPtr observ( - do_GetService("@mozilla.org/observer-service;1")); - if (observ) - observ->NotifyObservers(NS_STATIC_CAST(ipcIService *, this), - IPC_SERVICE_SHUTDOWN_TOPIC, nsnull); - - // error out any pending queries - while (mQueryQ.First()) { - ipcClientQuery *query = mQueryQ.First(); - query->OnQueryComplete(NS_ERROR_ABORT, NULL); - mQueryQ.DeleteFirst(); - } - - // disconnect any message observers - mObserverDB.Reset(ipcReleaseMessageObserver, nsnull); - - // drop daemon connection - if (mTransport) { - mTransport->Shutdown(); - mTransport = nsnull; - } - - mClientID = 0; -} - -void -ipcService::OnIPCMClientID(const ipcmMessageClientID *msg) -{ - LOG(("ipcService::OnIPCMClientID\n")); - - ipcClientQuery *query = mQueryQ.First(); - if (!query) { - NS_WARNING("no pending query; ignoring message."); - return; - } - - PRUint32 cID = msg->ClientID(); - PRBool sync = msg->TestFlag(IPC_MSG_FLAG_SYNC_REPLY); - - // - // (1) store client ID in query - // (2) move query to end of queue - // (3) issue CLIENT_INFO request - // - query->SetClientID(cID); - - mQueryQ.RemoveFirst(); - mQueryQ.Append(query); - - mTransport->SendMsg(new ipcmMessageQueryClientInfo(cID), sync); -} - -void -ipcService::OnIPCMClientInfo(const ipcmMessageClientInfo *msg) -{ - LOG(("ipcService::OnIPCMClientInfo\n")); - - ipcClientQuery *query = mQueryQ.First(); - if (!query) { - NS_WARNING("no pending query; ignoring message."); - return; - } - - if (!query->IsCanceled()) - query->OnQueryComplete(NS_OK, msg); - - mQueryQ.DeleteFirst(); -} - -void -ipcService::OnIPCMError(const ipcmMessageError *msg) -{ - LOG(("ipcService::OnIPCMError [reason=0x%08x]\n", msg->Reason())); - - ipcClientQuery *query = mQueryQ.First(); - if (!query) { - NS_WARNING("no pending query; ignoring message."); - return; - } - - if (!query->IsCanceled()) - query->OnQueryComplete(NS_ERROR_FAILURE, NULL); - - mQueryQ.DeleteFirst(); -} - -//----------------------------------------------------------------------------- -// interface impl -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS2(ipcService, ipcIService, nsIObserver) +NS_IMPL_ISUPPORTS1(ipcService, ipcIService) NS_IMETHODIMP -ipcService::GetClientID(PRUint32 *clientID) +ipcService::GetID(PRUint32 *aID) { - NS_ENSURE_TRUE(mClientID != 0, NS_ERROR_NOT_INITIALIZED); - - *clientID = mClientID; - return NS_OK; + return IPC_GetID(aID); } NS_IMETHODIMP -ipcService::AddClientName(const char *name) +ipcService::AddName(const char *aName) { - NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); - - ipcMessage *msg = new ipcmMessageClientAddName(name); - if (!msg) - return NS_ERROR_OUT_OF_MEMORY; - - return mTransport->SendMsg(msg); + return IPC_AddName(aName); } NS_IMETHODIMP -ipcService::RemoveClientName(const char *name) +ipcService::RemoveName(const char *aName) { - NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); - - ipcMessage *msg = new ipcmMessageClientDelName(name); - if (!msg) - return NS_ERROR_OUT_OF_MEMORY; - - return mTransport->SendMsg(msg); + return IPC_RemoveName(aName); } NS_IMETHODIMP -ipcService::QueryClientByName(const char *name, - ipcIClientQueryHandler *handler, - PRBool sync, - PRUint32 *queryID) +ipcService::AddClientObserver(ipcIClientObserver *aObserver) { - if (!mTransport) - return NS_ERROR_NOT_AVAILABLE; - - ipcMessage *msg; - - msg = new ipcmMessageQueryClientByName(name); - if (!msg) - return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv; - - rv = mTransport->SendMsg(msg, sync); - if (NS_FAILED(rv)) return rv; - - ipcClientQuery *query = new ipcClientQuery(0, handler); - if (queryID) - *queryID = query->QueryID(); - mQueryQ.Append(query); - return NS_OK; + return IPC_AddClientObserver(aObserver); } NS_IMETHODIMP -ipcService::QueryClientByID(PRUint32 clientID, - ipcIClientQueryHandler *handler, - PRBool sync, - PRUint32 *queryID) +ipcService::RemoveClientObserver(ipcIClientObserver *aObserver) { - if (!mTransport) - return NS_ERROR_NOT_AVAILABLE; - - ipcMessage *msg; - - msg = new ipcmMessageQueryClientInfo(clientID); - if (!msg) - return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv; - - rv = mTransport->SendMsg(msg, sync); - if (NS_FAILED(rv)) return rv; - - ipcClientQuery *query = new ipcClientQuery(clientID, handler); - if (queryID) - *queryID = query->QueryID(); - mQueryQ.Append(query); - return NS_OK; + return IPC_RemoveClientObserver(aObserver); } NS_IMETHODIMP -ipcService::CancelQuery(PRUint32 queryID) +ipcService::ResolveClientName(const char *aName, PRUint32 *aID) { - ipcClientQuery *query = mQueryQ.First(); - while (query) { - if (query->QueryID() == queryID) { - query->OnQueryComplete(NS_ERROR_ABORT, NULL); - break; - } - query = query->mNext; - } - return NS_OK; + return IPC_ResolveClientName(aName, aID); } NS_IMETHODIMP -ipcService::SetClientObserver(ipcIClientObserver *observer) +ipcService::ClientExists(PRUint32 aClientID, PRBool *aResult) { - return NS_ERROR_NOT_IMPLEMENTED; + return IPC_ClientExists(aClientID, aResult); } NS_IMETHODIMP -ipcService::SetMessageObserver(const nsID &target, ipcIMessageObserver *observer) +ipcService::DefineTarget(const nsID &aTarget, ipcIMessageObserver *aObserver) { - NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); - - nsIDKey key(target); - PRBool sendAdd = PR_TRUE; - - ipcIMessageObserver *cobs = (ipcIMessageObserver *) mObserverDB.Get(&key); - if (cobs) { - NS_RELEASE(cobs); - if (!observer) { - mObserverDB.Remove(&key); - // - // send CLIENT_DEL_TARGET - // - mTransport->SendMsg(new ipcmMessageClientDelTarget(target)); - return NS_OK; - } - sendAdd = PR_FALSE; - } - if (observer) { - NS_ADDREF(observer); - mObserverDB.Put(&key, observer); - if (sendAdd) { - // - // send CLIENT_ADD_TARGET - // - mTransport->SendMsg(new ipcmMessageClientAddTarget(target)); - } - } - return NS_OK; + return IPC_DefineTarget(aTarget, aObserver); } NS_IMETHODIMP -ipcService::SendMessage(PRUint32 clientID, - const nsID &target, - const PRUint8 *data, - PRUint32 dataLen, - PRBool sync) +ipcService::SendMessage(PRUint32 aReceiverID, const nsID &aTarget, + const PRUint8 *aData, PRUint32 aDataLen) { - NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); - - if (target.Equals(IPCM_TARGET)) { - NS_ERROR("do not try to talk to the IPCM target directly"); - return NS_ERROR_INVALID_ARG; - } - - ipcMessage *msg; - if (clientID) - msg = new ipcmMessageForward(clientID, target, (const char *) data, dataLen); - else - msg = new ipcMessage(target, (const char *) data, dataLen); - - if (!msg) - return NS_ERROR_OUT_OF_MEMORY; - - return mTransport->SendMsg(msg, sync); + return IPC_SendMessage(aReceiverID, aTarget, aData, aDataLen); } -//----------------------------------------------------------------------------- -// nsIObserver impl -//----------------------------------------------------------------------------- - NS_IMETHODIMP -ipcService::Observe(nsISupports *subject, const char *topic, const PRUnichar *data) +ipcService::WaitMessage(PRUint32 aSenderID, const nsID &aTarget, + ipcIMessageObserver *aObserver, + PRUint32 aTimeout) { - if (strcmp(topic, "xpcom-shutdown") == 0) - Shutdown(); - return NS_OK; -} - -//----------------------------------------------------------------------------- -// ipcTransportObserver impl -//----------------------------------------------------------------------------- - -void -ipcService::OnConnectionLost() -{ - Shutdown(); -} - -void -ipcService::OnMessageAvailable(const ipcMessage *msg) -{ - LOG(("ipcService::OnMessageAvailable [msg=%p]\n", msg)); - - if (msg->Target().Equals(IPCM_TARGET)) { - // - // all IPCM messages stop here. - // - PRUint32 type = IPCM_GetMsgType(msg); - switch (type) { - case IPCM_MSG_TYPE_CLIENT_ID: - OnIPCMClientID((const ipcmMessageClientID *) msg); - break; - case IPCM_MSG_TYPE_CLIENT_INFO: - OnIPCMClientInfo((const ipcmMessageClientInfo *) msg); - break; - case IPCM_MSG_TYPE_ERROR: - OnIPCMError((const ipcmMessageError *) msg); - break; - } - } - else { - nsIDKey key(msg->Target()); - ipcIMessageObserver *observer = (ipcIMessageObserver *) mObserverDB.Get(&key); - if (observer) - observer->OnMessageAvailable(msg->Target(), - (const PRUint8 *) msg->Data(), - msg->DataLen()); - } + return IPC_WaitMessage(aSenderID, aTarget, aObserver, PR_MillisecondsToInterval(aTimeout)); } diff --git a/mozilla/ipc/ipcd/client/src/ipcService.h b/mozilla/ipc/ipcd/client/src/ipcService.h index c1e8e13b7a5..fec78ff9c7a 100644 --- a/mozilla/ipc/ipcd/client/src/ipcService.h +++ b/mozilla/ipc/ipcd/client/src/ipcService.h @@ -38,52 +38,19 @@ #ifndef ipcService_h__ #define ipcService_h__ -#include "nsHashtable.h" -#include "nsAutoPtr.h" -#include "plevent.h" - #include "ipcIService.h" -#include "ipcTransport.h" -#include "ipcList.h" -#include "ipcMessage.h" -#include "ipcMessageQ.h" -#include "ipcm.h" - -typedef ipcList ipcClientQueryQ; - -//---------------------------------------------------------------------------- -// ipcService -//---------------------------------------------------------------------------- +#include "ipcdclient.h" class ipcService : public ipcIService - , public ipcTransportObserver - , public nsIObserver { public: NS_DECL_ISUPPORTS NS_DECL_IPCISERVICE - NS_DECL_NSIOBSERVER - ipcService(); - virtual ~ipcService(); - - nsresult Init(); - void Shutdown(); - - // ipcTransportObserver: - void OnConnectionLost(); - void OnMessageAvailable(const ipcMessage *); + NS_HIDDEN_(nsresult) Init() { return IPC_Init(); } private: - nsresult ErrorAccordingToIPCM(PRUint32 err); - void OnIPCMClientID(const ipcmMessageClientID *); - void OnIPCMClientInfo(const ipcmMessageClientInfo *); - void OnIPCMError(const ipcmMessageError *); - - nsHashtable mObserverDB; - nsRefPtr mTransport; - ipcClientQueryQ mQueryQ; - PRUint32 mClientID; + ~ipcService() { IPC_Shutdown(); } }; -#endif // !ipcService_h__ +#endif // !defined( ipcService_h__ ) diff --git a/mozilla/ipc/ipcd/client/src/ipcTransport.cpp b/mozilla/ipc/ipcd/client/src/ipcTransport.cpp index b2cff08e87e..252b09556c2 100644 --- a/mozilla/ipc/ipcd/client/src/ipcTransport.cpp +++ b/mozilla/ipc/ipcd/client/src/ipcTransport.cpp @@ -126,7 +126,7 @@ end: if (attr) PR_DestroyProcessAttr(attr); return rv; - } +} //----------------------------------------------------------------------------- // ipcTransport diff --git a/mozilla/ipc/ipcd/client/src/ipcdclient.cpp b/mozilla/ipc/ipcd/client/src/ipcdclient.cpp new file mode 100644 index 00000000000..f2d3ac0b05c --- /dev/null +++ b/mozilla/ipc/ipcd/client/src/ipcdclient.cpp @@ -0,0 +1,1129 @@ +/* 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 + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ipcdclient.h" +#include "ipcConnection.h" +#include "ipcConfig.h" +#include "ipcMessageQ.h" +#include "ipcMessageUtils.h" +#include "ipcLog.h" +#include "ipcm.h" + +#include "nsIFile.h" +#include "nsEventQueueUtils.h" +#include "nsDirectoryServiceUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCOMPtr.h" +#include "nsHashKeys.h" +#include "nsRefPtrHashtable.h" +#include "nsAutoLock.h" +#include "nsProxyRelease.h" +#include "nsCOMArray.h" + +#include "prio.h" +#include "prproces.h" +#include "prlock.h" +#include "pratom.h" + +/* ------------------------------------------------------------------------- */ + +#define IPC_REQUEST_TIMEOUT PR_SecondsToInterval(30) + +/* ------------------------------------------------------------------------- */ + +class ipcTargetData +{ +public: + static NS_HIDDEN_(ipcTargetData*) Create(ipcIMessageObserver *aObserver); + + // threadsafe addref/release + NS_HIDDEN_(nsrefcnt) AddRef() { return PR_AtomicIncrement(&refcnt); } + NS_HIDDEN_(nsrefcnt) Release() { PRInt32 r = PR_AtomicDecrement(&refcnt); if (r == 0) delete this; return r; } + + // protects access to the members of this class + PRMonitor *monitor; + + // this may be null + nsCOMPtr observer; + + // incoming messages are added to this list + ipcMessageQ pendingQ; + +private: + + ipcTargetData() + : monitor(PR_NewMonitor()) + , refcnt(0) + {} + + ~ipcTargetData() + { + if (monitor) + PR_DestroyMonitor(monitor); + } + + PRInt32 refcnt; +}; + +ipcTargetData * +ipcTargetData::Create(ipcIMessageObserver *aObserver) +{ + ipcTargetData *td = new ipcTargetData; + if (!td) + return NULL; + + if (!td->monitor) + { + delete td; + return NULL; + } + + td->observer = aObserver; + return td; +} + +/* ------------------------------------------------------------------------- */ + +typedef nsRefPtrHashtable ipcTargetMap; + +class ipcClientState +{ +public: + static NS_HIDDEN_(ipcClientState *) Create(); + + ~ipcClientState() + { + if (lock) + PR_DestroyLock(lock); + } + + // this lock protects the targetMap and the connected flag. + PRLock *lock; + ipcTargetMap targetMap; + PRBool connected; + + // our process's client id + PRUint32 selfID; + + nsCOMArray clientObservers; + +private: + + ipcClientState() + : lock(PR_NewLock()) + , connected(PR_FALSE) + , selfID(0) + {} +}; + +ipcClientState * +ipcClientState::Create() +{ + ipcClientState *cs = new ipcClientState; + if (!cs) + return NULL; + + if (!cs->lock || !cs->targetMap.Init()) + { + delete cs; + return NULL; + } + + return cs; +} + +/* ------------------------------------------------------------------------- */ + +static PRInt32 gInitCount; +static ipcClientState *gClientState; + +static PRBool +GetTarget(const nsID &aTarget, ipcTargetData **td) +{ + nsAutoLock lock(gClientState->lock); + return gClientState->targetMap.Get(nsIDHashKey(&aTarget).GetKey(), td); +} + +static PRBool +PutTarget(const nsID &aTarget, ipcTargetData *td) +{ + nsAutoLock lock(gClientState->lock); + return gClientState->targetMap.Put(nsIDHashKey(&aTarget).GetKey(), td); +} + +static void +DelTarget(const nsID &aTarget) +{ + nsAutoLock lock(gClientState->lock); + gClientState->targetMap.Remove(nsIDHashKey(&aTarget).GetKey()); +} + +/* ------------------------------------------------------------------------- */ + +static nsresult +GetDaemonPath(nsCString &dpath) +{ + nsCOMPtr file; + + nsresult rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, + getter_AddRefs(file)); + if (NS_SUCCEEDED(rv)) + { + rv = file->AppendNative(NS_LITERAL_CSTRING(IPC_DAEMON_APP_NAME)); + if (NS_SUCCEEDED(rv)) + rv = file->GetNativePath(dpath); + } + + return rv; +} + +/* ------------------------------------------------------------------------- */ + +static void +ProcessPendingQ(const nsID &aTarget) +{ + ipcMessageQ tempQ; + + nsRefPtr td; + if (GetTarget(aTarget, getter_AddRefs(td))) + { + nsAutoMonitor mon(td->monitor); + td->pendingQ.MoveTo(tempQ); + } + + // process pending queue outside monitor + while (!tempQ.IsEmpty()) + { + ipcMessage *msg = tempQ.First(); + + if (td->observer) + td->observer->OnMessageAvailable(msg->mMetaData, + msg->Target(), + (const PRUint8 *) msg->Data(), + msg->DataLen()); + else + { + // the IPCM target does not have an observer, and therefore any IPCM + // messages that make it here will simply be dropped. + NS_ASSERTION(aTarget.Equals(IPCM_TARGET), "unexpected target"); + LOG(("dropping IPCM message: type=%x\n", IPCM_GetType(msg))); + } + tempQ.DeleteFirst(); + } +} + +/* ------------------------------------------------------------------------- */ + +// WaitTarget enables support for multiple threads blocking on the same +// message target. This functionality does not need to be exposed in our +// public API because targets are meant to be single threaded. This +// functionality only exists to support the IPCM protocol. + +typedef PRBool (* ipcMessageSelector)(void *aArg, ipcTargetData *aTD, const ipcMessage *aMsg); + +static PRBool +DefaultSelector(void *aArg, ipcTargetData *aTD, const ipcMessage *aMsg) +{ + return PR_TRUE; +} + +static nsresult +WaitTarget(const nsID &aTarget, + PRIntervalTime aTimeout, + ipcMessage **aMsg, + ipcMessageSelector aSelector = nsnull, + void *aArg = nsnull) +{ + *aMsg = nsnull; + + if (!aSelector) + aSelector = DefaultSelector; + + nsRefPtr td; + if (!GetTarget(aTarget, getter_AddRefs(td))) + return NS_ERROR_INVALID_ARG; // bad aTarget + + PRIntervalTime timeStart = PR_IntervalNow(); + PRIntervalTime timeEnd; + if (aTimeout == PR_INTERVAL_NO_TIMEOUT) + timeEnd = aTimeout; + else if (aTimeout == PR_INTERVAL_NO_WAIT) + timeEnd = timeStart; + else + { + timeEnd = timeStart + aTimeout; + + // if overflowed, then set to max value + if (timeEnd < timeStart) + timeEnd = PR_INTERVAL_NO_TIMEOUT; + } + + ipcMessage *lastChecked = nsnull, *beforeLastChecked = nsnull; + nsresult rv = NS_ERROR_FAILURE; + + nsAutoMonitor mon(td->monitor); + + while (gClientState->connected) + { + if (!lastChecked) + { + if (beforeLastChecked) + lastChecked = beforeLastChecked->mNext; + else + lastChecked = td->pendingQ.First(); + } + else if (lastChecked->mNext) + lastChecked = lastChecked->mNext; + + while (lastChecked) + { + // remove this message from the pending queue. we'll put it back if + // it is not selected. we need to do this to allow the selector + // function to make calls back into our code. for example, it might + // try to undefine this message target! + + if (beforeLastChecked) + td->pendingQ.RemoveAfter(beforeLastChecked); + else + td->pendingQ.RemoveFirst(); + lastChecked->mNext = nsnull; + + mon.Exit(); + PRBool selected = (aSelector)(aArg, td, lastChecked); + mon.Enter(); + + if (selected) + { + *aMsg = lastChecked; + break; + } + + // re-insert message into the pending queue. the only possible change + // that could have happened to the pending queue while we were in the + // callback is the addition of more messages (added to the end of the + // queue). our beforeLastChecked "iterator" must still be valid. + +#ifdef DEBUG + // scan td->pendingQ to ensure that beforeLastChecked is still valid. + if (beforeLastChecked) + { + PRBool found = PR_FALSE; + for (ipcMessage *iter = td->pendingQ.First(); iter; iter = iter->mNext) + { + if (iter == beforeLastChecked) + { + found = PR_TRUE; + break; + } + } + NS_ASSERTION(found, "iterator is invalid"); + } +#endif + + if (beforeLastChecked) + td->pendingQ.InsertAfter(beforeLastChecked, lastChecked); + else + td->pendingQ.Prepend(lastChecked); + + beforeLastChecked = lastChecked; + lastChecked = lastChecked->mNext; + } + + if (*aMsg) + { + rv = NS_OK; + break; + } + + // make sure we are still connected before waiting... + if (!gClientState->connected) + { + rv = NS_ERROR_ABORT; + break; + } + + PRIntervalTime t = PR_IntervalNow(); + if (t > timeEnd) // check if timeout has expired + { + rv = IPC_ERROR_WOULD_BLOCK; + break; + } + mon.Wait(timeEnd - t); + } + + return rv; +} + +/* ------------------------------------------------------------------------- */ + +// selects the next IPCM message with matching request index +static PRBool +WaitIPCMResponseSelector(void *arg, ipcTargetData *td, const ipcMessage *msg) +{ + PRUint32 requestIndex = *(PRUint32 *) arg; + return IPCM_GetRequestIndex(msg) == requestIndex; +} + +// wait for an IPCM response message. if responseMsg is null, then it is +// assumed that the caller does not care to get a reference to the +// response itself. if the response is an IPCM_MSG_ACK_RESULT, then the +// status code is mapped to a nsresult and returned by this function. +static nsresult +WaitIPCMResponse(PRUint32 requestIndex, ipcMessage **responseMsg = nsnull) +{ + ipcMessage *msg; + + nsresult rv = WaitTarget(IPCM_TARGET, IPC_REQUEST_TIMEOUT, &msg, + WaitIPCMResponseSelector, &requestIndex); + if (NS_FAILED(rv)) + return rv; + + if (IPCM_GetType(msg) == IPCM_MSG_ACK_RESULT) + { + ipcMessageCast result(msg); + if (result->Status() < 0) + rv = NS_ERROR_FAILURE; // XXX nsresult_from_ipcm_result() + else + rv = NS_OK; + } + + if (responseMsg) + *responseMsg = msg; + else + delete msg; + + return rv; +} + +// make an IPCM request and wait for a response. +static nsresult +MakeIPCMRequest(ipcMessage *msg, ipcMessage **responseMsg = nsnull) +{ + if (!msg) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 requestIndex = IPCM_GetRequestIndex(msg); + + nsresult rv = IPC_SendMsg(msg); + if (NS_SUCCEEDED(rv)) + rv = WaitIPCMResponse(requestIndex, responseMsg); + return rv; +} + +/* ------------------------------------------------------------------------- */ + +static void +RemoveTarget(const nsID &aTarget, PRBool aNotifyDaemon) +{ + DelTarget(aTarget); + + if (aNotifyDaemon) + { + nsresult rv = MakeIPCMRequest(new ipcmMessageClientDelTarget(aTarget)); + if (NS_FAILED(rv)) + LOG(("failed to delete target: rv=%x\n", rv)); + } +} + +static nsresult +DefineTarget(const nsID &aTarget, + ipcIMessageObserver *aObserver, + PRBool aNotifyDaemon, + ipcTargetData **aResult) +{ + nsresult rv; + + nsRefPtr td( ipcTargetData::Create(aObserver) ); + if (!td) + return NS_ERROR_OUT_OF_MEMORY; + + if (!PutTarget(aTarget, td)) + return NS_ERROR_OUT_OF_MEMORY; + + if (aNotifyDaemon) + { + rv = MakeIPCMRequest(new ipcmMessageClientAddTarget(aTarget)); + if (NS_FAILED(rv)) + { + LOG(("failed to add target: rv=%x\n", rv)); + RemoveTarget(aTarget, PR_FALSE); + return rv; + } + } + + if (aResult) + NS_ADDREF(*aResult = td); + return NS_OK; +} + +/* ------------------------------------------------------------------------- */ + +static nsresult +TryConnect() +{ + nsCAutoString dpath; + nsresult rv = GetDaemonPath(dpath); + if (NS_FAILED(rv)) + return rv; + + rv = IPC_Connect(dpath.get()); + if (NS_FAILED(rv)) + return rv; + + gClientState->connected = PR_TRUE; + + rv = DefineTarget(IPCM_TARGET, nsnull, PR_FALSE, nsnull); + if (NS_FAILED(rv)) + return rv; + + ipcMessage *msg; + + // send CLIENT_HELLO and wait for CLIENT_ID response... + rv = MakeIPCMRequest(new ipcmMessageClientHello(), &msg); + if (NS_FAILED(rv)) + return rv; + + if (IPCM_GetType(msg) == IPCM_MSG_ACK_CLIENT_ID) + gClientState->selfID = ipcMessageCast(msg)->ClientID(); + else + { + LOG(("unexpected response from CLIENT_HELLO message: type=%x!\n", + IPCM_GetType(msg))); + rv = NS_ERROR_UNEXPECTED; + } + + delete msg; + return rv; +} + +nsresult +IPC_Init() +{ + if (gInitCount > 0) + return NS_OK; + + IPC_InitLog(">>>"); + + gClientState = ipcClientState::Create(); + if (!gClientState) + return NS_ERROR_OUT_OF_MEMORY; + + // IPC_Shutdown will decrement + gInitCount++; + + nsresult rv = TryConnect(); + if (NS_FAILED(rv)) + IPC_Shutdown(); + + return rv; +} + +nsresult +IPC_Shutdown() +{ + NS_ENSURE_TRUE(gInitCount, NS_ERROR_NOT_INITIALIZED); + + if (--gInitCount > 0) + return NS_OK; + + if (gClientState->connected) + IPC_Disconnect(); + + delete gClientState; + gClientState = NULL; + + return NS_OK; +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_DefineTarget(const nsID &aTarget, + ipcIMessageObserver *aObserver) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + // do not permit the re-definition of the IPCM protocol's target. + if (aTarget.Equals(IPCM_TARGET)) + return NS_ERROR_INVALID_ARG; + + nsresult rv; + + nsRefPtr td; + if (GetTarget(aTarget, getter_AddRefs(td))) + { + // clear out observer before removing target since we want to ensure that + // the observer is released on the main thread. + { + nsAutoMonitor mon(td->monitor); + td->observer = aObserver; + } + + // remove target outside of td's monitor to avoid holding the monitor + // while entering the client state's lock. + if (!aObserver) + RemoveTarget(aTarget, PR_TRUE); + + rv = NS_OK; + } + else + { + if (aObserver) + rv = DefineTarget(aTarget, aObserver, PR_TRUE, nsnull); + else + rv = NS_ERROR_INVALID_ARG; // unknown target + } + + return rv; +} + +nsresult +IPC_SendMessage(PRUint32 aReceiverID, + const nsID &aTarget, + const PRUint8 *aData, + PRUint32 aDataLen) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + // do not permit sending IPCM messages + if (aTarget.Equals(IPCM_TARGET)) + return NS_ERROR_INVALID_ARG; + + nsresult rv; + if (aReceiverID == 0) + { + ipcMessage *msg = new ipcMessage(aTarget, (const char *) aData, aDataLen); + if (!msg) + return NS_ERROR_OUT_OF_MEMORY; + + rv = IPC_SendMsg(msg); + } + else + rv = MakeIPCMRequest(new ipcmMessageForward(IPCM_MSG_REQ_FORWARD, + aReceiverID, + aTarget, + (const char *) aData, + aDataLen)); + + return rv; +} + +struct WaitMessageSelectorData +{ + PRUint32 senderID; + ipcIMessageObserver *observer; +}; + +static PRBool WaitMessageSelector(void *arg, ipcTargetData *td, const ipcMessage *msg) +{ + WaitMessageSelectorData *data = (WaitMessageSelectorData *) arg; + + nsresult rv = IPC_WAIT_NEXT_MESSAGE; + + if (msg->mMetaData == data->senderID) + { + ipcIMessageObserver *obs = data->observer; + if (!obs) + obs = td->observer; + NS_ASSERTION(obs, "must at least have a default observer"); + + rv = obs->OnMessageAvailable(msg->mMetaData, + msg->Target(), + (const PRUint8 *) msg->Data(), + msg->DataLen()); + } + + // stop iterating if we got a match that the observer accepted. + return rv != IPC_WAIT_NEXT_MESSAGE; +} + +nsresult +IPC_WaitMessage(PRUint32 aSenderID, + const nsID &aTarget, + ipcIMessageObserver *aObserver, + PRIntervalTime aTimeout) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + // do not permit waiting for IPCM messages + if (aTarget.Equals(IPCM_TARGET)) + return NS_ERROR_INVALID_ARG; + + WaitMessageSelectorData data = { aSenderID, aObserver }; + + ipcMessage *msg; + nsresult rv = WaitTarget(aTarget, aTimeout, &msg, WaitMessageSelector, &data); + if (NS_FAILED(rv)) + return rv; + delete msg; + + return NS_OK; +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_GetID(PRUint32 *aClientID) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + *aClientID = gClientState->selfID; + return NS_OK; +} + +nsresult +IPC_AddName(const char *aName) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + return MakeIPCMRequest(new ipcmMessageClientAddName(aName)); +} + +nsresult +IPC_RemoveName(const char *aName) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + return MakeIPCMRequest(new ipcmMessageClientDelName(aName)); +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_AddClientObserver(ipcIClientObserver *aObserver) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + return gClientState->clientObservers.AppendObject(aObserver) + ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult +IPC_RemoveClientObserver(ipcIClientObserver *aObserver) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + for (PRInt32 i = 0; i < gClientState->clientObservers.Count(); ++i) + { + if (gClientState->clientObservers[i] == aObserver) + gClientState->clientObservers.RemoveObjectAt(i); + } + + return NS_OK; +} + +/* ------------------------------------------------------------------------- */ + +// this function could be called on any thread +nsresult +IPC_ResolveClientName(const char *aName, PRUint32 *aClientID) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + ipcMessage *msg; + + nsresult rv = MakeIPCMRequest(new ipcmMessageQueryClientByName(aName), &msg); + if (NS_FAILED(rv)) + return rv; + + if (IPCM_GetType(msg) == IPCM_MSG_ACK_CLIENT_ID) + *aClientID = ipcMessageCast(msg)->ClientID(); + else + { + LOG(("unexpected IPCM response: type=%x\n", IPCM_GetType(msg))); + rv = NS_ERROR_UNEXPECTED; + } + + delete msg; + return rv; +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_ClientExists(PRUint32 aClientID, PRBool *aResult) +{ + // this is a bit of a hack. we forward a PING to the specified client. + // the assumption is that the forwarding will only succeed if the client + // exists, so we wait for the RESULT message corresponding to the FORWARD + // request. if that gives a successful status, then we know that the + // client exists. + + ipcmMessagePing ping; + + return MakeIPCMRequest(new ipcmMessageForward(IPCM_MSG_REQ_FORWARD, + aClientID, + IPCM_TARGET, + ping.Data(), + ping.DataLen())); +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_SpawnDaemon(const char *path) +{ + PRFileDesc *readable = NULL, *writable = NULL; + PRProcessAttr *attr = NULL; + nsresult rv = NS_ERROR_FAILURE; + char *const argv[] = { (char *const) path, NULL }; + char c; + + // setup an anonymous pipe that we can use to determine when the daemon + // process has started up. the daemon will write a char to the pipe, and + // when we read it, we'll know to proceed with trying to connect to the + // daemon. + + if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS) + goto end; + PR_SetFDInheritable(writable, PR_TRUE); + + attr = PR_NewProcessAttr(); + if (!attr) + goto end; + + if (PR_ProcessAttrSetInheritableFD(attr, writable, IPC_STARTUP_PIPE_NAME) != PR_SUCCESS) + goto end; + + if (PR_CreateProcessDetached(path, argv, NULL, attr) != PR_SUCCESS) + goto end; + + if ((PR_Read(readable, &c, 1) != 1) && (c != IPC_STARTUP_PIPE_MAGIC)) + goto end; + + rv = NS_OK; +end: + if (readable) + PR_Close(readable); + if (writable) + PR_Close(writable); + if (attr) + PR_DestroyProcessAttr(attr); + return rv; +} + +/* ------------------------------------------------------------------------- */ + +class ipcEvent_ClientState : public PLEvent +{ +public: + ipcEvent_ClientState(PRUint32 aClientID, PRUint32 aClientState) + : mClientID(aClientID) + , mClientState(aClientState) + { + PL_InitEvent(this, nsnull, HandleEvent, DestroyEvent); + } + + PR_STATIC_CALLBACK(void *) HandleEvent(PLEvent *ev) + { + // maybe we've been shutdown! + if (!gClientState) + return nsnull; + + ipcEvent_ClientState *self = (ipcEvent_ClientState *) ev; + + for (PRInt32 i=0; iclientObservers.Count(); ++i) + gClientState->clientObservers[i]->OnClientStateChange(self->mClientID, + self->mClientState); + return nsnull; + } + + PR_STATIC_CALLBACK(void) DestroyEvent(PLEvent *ev) + { + delete (ipcEvent_ClientState *) ev; + } + +private: + PRUint32 mClientID; + PRUint32 mClientState; +}; + +/* ------------------------------------------------------------------------- */ + +class ipcEvent_ProcessPendingQ : public PLEvent +{ +public: + ipcEvent_ProcessPendingQ(const nsID &aTarget) + : mTarget(aTarget) + { + PL_InitEvent(this, nsnull, HandleEvent, DestroyEvent); + } + + PR_STATIC_CALLBACK(void *) HandleEvent(PLEvent *ev) + { + ProcessPendingQ(((ipcEvent_ProcessPendingQ *) ev)->mTarget); + return nsnull; + } + + PR_STATIC_CALLBACK(void) DestroyEvent(PLEvent *ev) + { + delete (ipcEvent_ProcessPendingQ *) ev; + } + +private: + const nsID mTarget; +}; + +/* ------------------------------------------------------------------------- */ + +static void +PostEvent(PLEvent *ev) +{ + if (!ev) + return; + + nsCOMPtr eventQ; + NS_GetMainEventQ(getter_AddRefs(eventQ)); + if (!eventQ) + return; + + nsresult rv = eventQ->PostEvent(ev); + if (NS_FAILED(rv)) + { + NS_WARNING("PostEvent failed"); + PL_DestroyEvent(ev); + } +} + +/* ------------------------------------------------------------------------- */ + +PR_STATIC_CALLBACK(PLDHashOperator) +EnumerateTargetMapAndNotify(const nsID &aKey, + ipcTargetData *aData, + void *aClosure) +{ + nsAutoMonitor mon(aData->monitor); + + // this flag needs to be set while we are inside the monitor, since it is one + // of the conditions under which WaitTarget may block waiting for messages. + gClientState->connected = PR_FALSE; + + // wake up anyone waiting on this target. + mon.Notify(); + + return PL_DHASH_NEXT; +} + +// called on a background thread +void +IPC_OnConnectionEnd(nsresult error) +{ + // now, go through the target map, and tickle each monitor. that should + // unblock any calls to WaitTarget. + + nsAutoLock lock(gClientState->lock); + gClientState->targetMap.EnumerateRead(EnumerateTargetMapAndNotify, nsnull); +} + +/* ------------------------------------------------------------------------- */ + +// called on a background thread +void +IPC_OnMessageAvailable(ipcMessage *msg) +{ + if (msg->Target().Equals(IPCM_TARGET)) + { + switch (IPCM_GetType(msg)) + { + // if this is a forwarded message, then post the inner message instead. + case IPCM_MSG_PSH_FORWARD: + { + ipcMessageCast fwd(msg); + ipcMessage *innerMsg = new ipcMessage(fwd->InnerTarget(), + fwd->InnerData(), + fwd->InnerDataLen()); + // store the sender's client id in the meta-data field of the message. + innerMsg->mMetaData = fwd->ClientID(); + + delete msg; + + // recurse so we can handle forwarded IPCM messages + IPC_OnMessageAvailable(innerMsg); + return; + } + case IPCM_MSG_PSH_CLIENT_STATE: + { + ipcMessageCast status(msg); + PostEvent(new ipcEvent_ClientState(status->ClientID(), + status->ClientState())); + return; + } + } + } + + nsRefPtr td; + if (GetTarget(msg->Target(), getter_AddRefs(td))) + { + nsAutoMonitor mon(td->monitor); + + PRBool dispatchEvent = td->pendingQ.IsEmpty(); + + // put this message on our pending queue + td->pendingQ.Append(msg); + + // wake up anyone waiting on this queue + mon.Notify(); + + // proxy call to target's message procedure + if (dispatchEvent) + PostEvent(new ipcEvent_ProcessPendingQ(msg->Target())); + } + else + { + NS_WARNING("message target is undefined"); + } +} + +/* ------------------------------------------------------------------------- */ + +#ifdef BUILD_IPCDCLIENT_STANDALONE + +#include "nsXPCOM.h" +#include "nsIEventQueueService.h" + +static PRBool gKeepGoing = PR_TRUE; + +static const nsID kTestTargetID = +{ /* e628fc6e-a6a7-48c7-adba-f241d1128fb8 */ + 0xe628fc6e, + 0xa6a7, + 0x48c7, + {0xad, 0xba, 0xf2, 0x41, 0xd1, 0x12, 0x8f, 0xb8} +}; + +class TestMessageObserver : public ipcIMessageObserver +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD OnMessageAvailable(PRUint32 aSenderID, + const nsID &aTarget, + const PRUint8 *aData, + PRUint32 aDataLen) + { + LOG(("got message from %d: \"%s\"\n", aSenderID, aData)); + return NS_OK; + } +}; +NS_IMPL_ISUPPORTS1(TestMessageObserver, ipcIMessageObserver) + +class TestClientObserver : public ipcIClientObserver +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD OnClientStateChange(PRUint32 aClientID, + PRUint32 aClientStatus) + { + LOG(("got client status change [cid=%u status=%u]\n", aClientID, aClientStatus)); + return NS_OK; + } +}; +NS_IMPL_ISUPPORTS1(TestClientObserver, ipcIClientObserver) + +int main() +{ + NS_InitXPCOM2(nsnull, nsnull, nsnull); + + { + nsresult rv; + + nsCOMPtr eqs = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return -1; + + rv = eqs->CreateMonitoredThreadEventQueue(); + if (NS_FAILED(rv)) return -1; + + nsCOMPtr eq; + rv = eqs->ResolveEventQueue(NS_CURRENT_EVENTQ, getter_AddRefs(eq)); + if (NS_FAILED(rv)) return -1; + + rv = IPC_Init(); + if (NS_FAILED(rv)) return -1; + + rv = IPC_AddClientObserver(new TestClientObserver()); + if (NS_FAILED(rv)) return -1; + + PRUint32 cID; + rv = IPC_GetID(&cID); + if (NS_FAILED(rv)) return -1; + + LOG(("current process's client id = %lu\n", cID)); + + // add test code here + + rv = IPC_AddName("ipcdclient"); + if (NS_FAILED(rv)) return -1; + + // test valid lookup + PRUint32 resolvedID; + rv = IPC_ResolveClientName("ipcdclient", &resolvedID); + if (NS_FAILED(rv)) return -1; + LOG(("resolved ID is %lu\n", resolvedID)); + if (resolvedID != cID) + NS_NOTREACHED("resolved ID is not what was expected"); + + // test bogus lookup + rv = IPC_ResolveClientName("foopy", &resolvedID); + LOG(("resolving \"foopy\" returned rv=%x\n", rv)); + if (NS_SUCCEEDED(rv)) + NS_NOTREACHED("expected client name lookup to fail"); + + rv = IPC_DefineTarget(kTestTargetID, new TestMessageObserver()); + if (NS_FAILED(rv)) return -1; + + const PRUint8 kData[] = "hello world\n"; + rv = IPC_SendMessage(0, kTestTargetID, kData, sizeof(kData)); + if (NS_FAILED(rv)) return -1; + + PLEvent *ev; + while (gKeepGoing) + { + eq->WaitForEvent(&ev); + if (!ev) + break; + eq->HandleEvent(ev); + } + + IPC_Shutdown(); + } + + NS_ShutdownXPCOM(nsnull); + return 0; +} + +#endif // BUILD_IPCDCLIENT_STANDALONE diff --git a/mozilla/ipc/ipcd/daemon/src/ipcCommandModule.cpp b/mozilla/ipc/ipcd/daemon/src/ipcCommandModule.cpp index eaba08932f3..e96b14a59fa 100644 --- a/mozilla/ipc/ipcd/daemon/src/ipcCommandModule.cpp +++ b/mozilla/ipc/ipcd/daemon/src/ipcCommandModule.cpp @@ -107,7 +107,7 @@ struct ipcCommandModule { LOG(("got PING\n")); - IPC_SendMsg(client, new ipcmMessagePing()); + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); } static void @@ -115,7 +115,7 @@ struct ipcCommandModule { LOG(("got CLIENT_HELLO\n")); - IPC_SendMsg(client, new ipcmMessageClientID(client->ID())); + IPC_SendMsg(client, new ipcmMessageClientID(IPCM_GetRequestIndex(rawMsg), client->ID())); // // NOTE: it would almost make sense for this notification to live @@ -136,6 +136,9 @@ struct ipcCommandModule const char *name = msg->Name(); if (name) client->AddName(name); + + // TODO: send better status code (e.g., suppose name already defined for client) + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); } static void @@ -147,6 +150,9 @@ struct ipcCommandModule const char *name = msg->Name(); if (name) client->DelName(name); + + // TODO: send better status code (e.g., suppose name not defined for client) + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); } static void @@ -156,6 +162,9 @@ struct ipcCommandModule ipcMessageCast msg(rawMsg); client->AddTarget(msg->Target()); + + // TODO: send better status code (e.g., suppose target already defined for client) + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); } static void @@ -165,6 +174,9 @@ struct ipcCommandModule ipcMessageCast msg(rawMsg); client->DelTarget(msg->Target()); + + // TODO: send better status code (e.g., suppose target not defined for client) + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); } static void @@ -172,18 +184,22 @@ struct ipcCommandModule { LOG(("got QUERY_CLIENT_BY_NAME\n")); + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + ipcMessageCast msg(rawMsg); + ipcClient *result = IPC_GetClientByName(msg->Name()); if (result) { LOG((" client exists w/ ID = %u\n", result->ID())); - IPC_SendMsg(client, new ipcmMessageClientID(result->ID())); + IPC_SendMsg(client, new ipcmMessageClientID(requestIndex, result->ID())); } else { LOG((" client does not exist\n")); - IPC_SendMsg(client, new ipcmMessageError(IPCM_ERROR_CLIENT_NOT_FOUND)); + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, IPCM_ERROR_NO_CLIENT)); } } +#if 0 static void OnQueryClientInfo(ipcClient *client, const ipcMessage *rawMsg) { @@ -196,6 +212,7 @@ struct ipcCommandModule nsID **targets = BuildIDArray(result->Targets()); IPC_SendMsg(client, new ipcmMessageClientInfo(result->ID(), + msg->RequestIndex(), (const char **) names, (const nsID **) targets)); @@ -204,9 +221,10 @@ struct ipcCommandModule } else { LOG((" client does not exist\n")); - IPC_SendMsg(client, new ipcmMessageError(IPCM_ERROR_CLIENT_NOT_FOUND)); + IPC_SendMsg(client, new ipcmMessageError(IPCM_ERROR_CLIENT_NOT_FOUND, msg->RequestIndex())); } } +#endif static void OnForward(ipcClient *client, const ipcMessage *rawMsg) @@ -215,14 +233,20 @@ struct ipcCommandModule ipcMessageCast msg(rawMsg); - ipcClient *dest = IPC_GetClientByID(msg->DestClientID()); + ipcClient *dest = IPC_GetClientByID(msg->ClientID()); if (!dest) { LOG((" destination client not found!\n")); + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_ERROR_NO_CLIENT)); return; } - ipcMessage *newMsg = new ipcMessage(msg->InnerTarget(), - msg->InnerData(), - msg->InnerDataLen()); + // inform client that its message will be forwarded + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); + + ipcMessage *newMsg = new ipcmMessageForward(IPCM_MSG_PSH_FORWARD, + client->ID(), + msg->InnerTarget(), + msg->InnerData(), + msg->InnerDataLen()); IPC_SendMsg(dest, newMsg); } }; @@ -233,26 +257,29 @@ IPCM_HandleMsg(ipcClient *client, const ipcMessage *rawMsg) static ipcCommandModule::MsgHandler handlers[] = { ipcCommandModule::OnPing, - NULL, // ERROR + ipcCommandModule::OnForward, ipcCommandModule::OnClientHello, - NULL, // CLIENT_ID - NULL, // CLIENT_INFO ipcCommandModule::OnClientAddName, ipcCommandModule::OnClientDelName, ipcCommandModule::OnClientAddTarget, ipcCommandModule::OnClientDelTarget, - ipcCommandModule::OnQueryClientByName, - ipcCommandModule::OnQueryClientInfo, - ipcCommandModule::OnForward, + ipcCommandModule::OnQueryClientByName }; - int type = IPCM_GetMsgType(rawMsg); - LOG(("IPCM_HandleMsg [type=%d]\n", type)); + int type = IPCM_GetType(rawMsg); + LOG(("IPCM_HandleMsg [type=%x]\n", type)); - if (type < IPCM_MSG_TYPE_UNKNOWN) { - if (handlers[type]) { - ipcCommandModule::MsgHandler handler = handlers[type]; - handler(client, rawMsg); - } + if (!(type & IPCM_MSG_CLASS_REQ)) { + LOG(("not a request -- ignoring message\n")); + return; } + + type &= ~IPCM_MSG_CLASS_REQ; + type--; + if (type < 0 || type >= (int) (sizeof(handlers)/sizeof(handlers[0]))) { + LOG(("unknown request -- ignoring message\n")); + return; + } + + (handlers[type])(client, rawMsg); } diff --git a/mozilla/ipc/ipcd/daemon/src/ipcModuleReg.cpp b/mozilla/ipc/ipcd/daemon/src/ipcModuleReg.cpp index 74601566dcd..09e60ab98cb 100644 --- a/mozilla/ipc/ipcd/daemon/src/ipcModuleReg.cpp +++ b/mozilla/ipc/ipcd/daemon/src/ipcModuleReg.cpp @@ -211,7 +211,7 @@ IPC_ShutdownModuleReg() } void -IPC_NotifyClientUp(ipcClient *client) +IPC_NotifyModulesClientUp(ipcClient *client) { for (int i = 0; i < ipcModuleCount; ++i) { ipcModuleRegEntry &entry = ipcModules[i]; @@ -221,7 +221,7 @@ IPC_NotifyClientUp(ipcClient *client) } void -IPC_NotifyClientDown(ipcClient *client) +IPC_NotifyModulesClientDown(ipcClient *client) { for (int i = 0; i < ipcModuleCount; ++i) { ipcModuleRegEntry &entry = ipcModules[i]; diff --git a/mozilla/ipc/ipcd/daemon/src/ipcModuleReg.h b/mozilla/ipc/ipcd/daemon/src/ipcModuleReg.h index c9eb68ef61e..d3fecd6c051 100644 --- a/mozilla/ipc/ipcd/daemon/src/ipcModuleReg.h +++ b/mozilla/ipc/ipcd/daemon/src/ipcModuleReg.h @@ -64,7 +64,7 @@ ipcModuleMethods *IPC_GetModuleByTarget(const nsID &target); // // notifies all modules of client connect/disconnect // -void IPC_NotifyClientUp(ipcClient *); -void IPC_NotifyClientDown(ipcClient *); +void IPC_NotifyModulesClientUp(ipcClient *); +void IPC_NotifyModulesClientDown(ipcClient *); #endif // !ipcModuleReg_h__ diff --git a/mozilla/ipc/ipcd/daemon/src/ipcd.cpp b/mozilla/ipc/ipcd/daemon/src/ipcd.cpp index 78cfe7e2fab..d91bdbdf66f 100644 --- a/mozilla/ipc/ipcd/daemon/src/ipcd.cpp +++ b/mozilla/ipc/ipcd/daemon/src/ipcd.cpp @@ -73,6 +73,8 @@ IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg) // next message sent to the client. if (msg->TestFlag(IPC_MSG_FLAG_SYNC_QUERY)) { PR_ASSERT(client->GetExpectsSyncReply() == PR_FALSE); + // XXX shouldn't we remember the TargetID as well, and only set the + // SYNC_REPLY flag on the next message sent to the same TargetID? client->SetExpectsSyncReply(PR_TRUE); } @@ -112,6 +114,32 @@ IPC_SendMsg(ipcClient *client, ipcMessage *msg) return PR_FAILURE; } +void +IPC_NotifyClientUp(ipcClient *client) +{ + // notify modules before other clients + IPC_NotifyModulesClientUp(client); + + for (int i=0; iID(), IPCM_CLIENT_STATE_UP)); + } +} + +void +IPC_NotifyClientDown(ipcClient *client) +{ + // notify modules before other clients + IPC_NotifyModulesClientDown(client); + + for (int i=0; iID(), IPCM_CLIENT_STATE_DOWN)); + } +} + //----------------------------------------------------------------------------- // IPC daemon methods //----------------------------------------------------------------------------- diff --git a/mozilla/ipc/ipcd/daemon/src/ipcd.h b/mozilla/ipc/ipcd/daemon/src/ipcd.h index f9182a6ef3f..5a0f2c2aadb 100644 --- a/mozilla/ipc/ipcd/daemon/src/ipcd.h +++ b/mozilla/ipc/ipcd/daemon/src/ipcd.h @@ -73,4 +73,10 @@ PRStatus IPC_DispatchMsg(ipcClientHandle client, const ipcMessage *msg); // PRStatus IPC_SendMsg(ipcClientHandle client, ipcMessage *msg); +// +// dispatch notifications about client connects and disconnects +// +void IPC_NotifyClientUp(ipcClientHandle client); +void IPC_NotifyClientDown(ipcClientHandle client); + #endif // !IPCD_H__ diff --git a/mozilla/ipc/ipcd/extensions/lock/public/Makefile.in b/mozilla/ipc/ipcd/extensions/lock/public/Makefile.in index 020b229ffee..a855ef128e8 100644 --- a/mozilla/ipc/ipcd/extensions/lock/public/Makefile.in +++ b/mozilla/ipc/ipcd/extensions/lock/public/Makefile.in @@ -45,6 +45,10 @@ include $(DEPTH)/config/autoconf.mk MODULE = ipcd +EXPORTS = \ + ipcLockCID.h \ + $(NULL) + XPIDLSRCS = \ ipcILockService.idl \ ipcILockNotify.idl \ diff --git a/mozilla/ipc/ipcd/extensions/lock/public/ipcILockService.idl b/mozilla/ipc/ipcd/extensions/lock/public/ipcILockService.idl index 7a9fb9565f0..a0457039bb3 100644 --- a/mozilla/ipc/ipcd/extensions/lock/public/ipcILockService.idl +++ b/mozilla/ipc/ipcd/extensions/lock/public/ipcILockService.idl @@ -74,18 +74,3 @@ interface ipcILockService : nsISupports */ void releaseLock(in string aLockName); }; - -%{C++ -// singleton implementing ipcILockService -#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} \ -} -%} diff --git a/mozilla/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h b/mozilla/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h index 0558da68112..b74b5cde889 100644 --- a/mozilla/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h +++ b/mozilla/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h @@ -79,7 +79,8 @@ struct ipcLockMsg PRUint8 *IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen); // -// unflatten a lock message +// 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); diff --git a/mozilla/ipc/ipcd/extensions/lock/src/ipcLockService.cpp b/mozilla/ipc/ipcd/extensions/lock/src/ipcLockService.cpp index 750c9702e51..aa8e3e999cd 100644 --- a/mozilla/ipc/ipcd/extensions/lock/src/ipcLockService.cpp +++ b/mozilla/ipc/ipcd/extensions/lock/src/ipcLockService.cpp @@ -42,29 +42,23 @@ #include "ipcLockProtocol.h" #include "ipcLog.h" -static NS_DEFINE_IID(kIPCServiceCID, IPC_SERVICE_CID); static const nsID kLockTargetID = IPC_LOCK_TARGETID; -ipcLockService::ipcLockService() -{ -} - -ipcLockService::~ipcLockService() -{ -} +//----------------------------------------------------------------------------- nsresult ipcLockService::Init() { nsresult rv; - mIPCService = do_GetService(kIPCServiceCID, &rv); - if (NS_FAILED(rv)) return rv; + rv = IPC_Init(); + if (NS_FAILED(rv)) + return rv; - return mIPCService->SetMessageObserver(kLockTargetID, this); + return IPC_DefineTarget(kLockTargetID, this); } -NS_IMPL_ISUPPORTS1(ipcLockService, ipcILockService) +NS_IMPL_ISUPPORTS2(ipcLockService, ipcILockService, ipcIMessageObserver) NS_IMETHODIMP ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool waitIfBusy) @@ -82,7 +76,7 @@ ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool if (!buf) return NS_ERROR_OUT_OF_MEMORY; - nsresult rv = mIPCService->SendMessage(0, kLockTargetID, buf, bufLen, (notify == nsnull)); + nsresult rv = IPC_SendMessage(0, kLockTargetID, buf, bufLen); free(buf); if (NS_FAILED(rv)) { LOG((" SendMessage failed [rv=%x]\n", rv)); @@ -92,9 +86,16 @@ ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool if (notify) { nsCStringKey hashKey(lockName); mPendingTable.Put(&hashKey, notify); + return NS_OK; } - return NS_OK; + // block the calling thread until we get a response from the daemon + + mSyncLockName = lockName; + rv = IPC_WaitMessage(0, kLockTargetID, nsnull, PR_INTERVAL_NO_TIMEOUT); + mSyncLockName = nsnull; + + return NS_FAILED(rv) ? rv : mSyncLockStatus; } NS_IMETHODIMP @@ -112,7 +113,7 @@ ipcLockService::ReleaseLock(const char *lockName) if (!buf) return NS_ERROR_OUT_OF_MEMORY; - nsresult rv = mIPCService->SendMessage(0, kLockTargetID, buf, bufLen, PR_FALSE); + nsresult rv = IPC_SendMessage(0, kLockTargetID, buf, bufLen); free(buf); if (NS_FAILED(rv)) return rv; @@ -123,12 +124,13 @@ ipcLockService::ReleaseLock(const char *lockName) } NS_IMETHODIMP -ipcLockService::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUint32 dataLen) +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)); + LOG(("ipcLockService::OnMessageAvailable [lock=%s opcode=%u sync-lock=%s]\n", msg.key, msg.opcode, mSyncLockName)); nsresult status; if (msg.opcode == IPC_LOCK_OP_STATUS_ACQUIRED) @@ -136,6 +138,16 @@ ipcLockService::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUi else status = NS_ERROR_FAILURE; + // handle synchronous waiting case first + if (mSyncLockName) { + if (strcmp(mSyncLockName, msg.key) == 0) { + mSyncLockStatus = status; + return NS_OK; + } + return IPC_WAIT_NEXT_MESSAGE; + } + + // otherwise, this is an asynchronous notification NotifyComplete(msg.key, status); return NS_OK; } diff --git a/mozilla/ipc/ipcd/extensions/lock/src/ipcLockService.h b/mozilla/ipc/ipcd/extensions/lock/src/ipcLockService.h index cc87a20bcc6..924f26f9f9d 100644 --- a/mozilla/ipc/ipcd/extensions/lock/src/ipcLockService.h +++ b/mozilla/ipc/ipcd/extensions/lock/src/ipcLockService.h @@ -39,9 +39,8 @@ #define ipcLockService_h__ #include "ipcILockService.h" -#include "ipcIService.h" -#include "ipcIMessageObserver.h" #include "ipcList.h" +#include "ipcdclient.h" #include "nsCOMPtr.h" #include "nsHashtable.h" @@ -53,18 +52,20 @@ public: NS_DECL_IPCILOCKSERVICE NS_DECL_IPCIMESSAGEOBSERVER - ipcLockService(); - virtual ~ipcLockService(); - - nsresult Init(); + ipcLockService() : mSyncLockName(nsnull) {} + ~ipcLockService() { IPC_Shutdown(); } + NS_HIDDEN_(nsresult) Init(); private: - void NotifyComplete(const char *lockName, nsresult status); - - nsCOMPtr mIPCService; + NS_HIDDEN_(void) NotifyComplete(const char *lockName, nsresult status); // map from lockname to locknotify for pending notifications - nsSupportsHashtable mPendingTable; + nsSupportsHashtable mPendingTable; + + // if non-null, then this is the name of the lock we are trying to + // synchronously acquire. + const char *mSyncLockName; + nsresult mSyncLockStatus; }; #endif // !ipcLockService_h__ diff --git a/mozilla/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp b/mozilla/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp index d803a543f31..32a9816fd49 100644 --- a/mozilla/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp +++ b/mozilla/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp @@ -119,66 +119,76 @@ ipcLockModule_AcquireLock(PRUint32 cid, PRUint8 flags, const char *key) } } -static void -ipcLockModule_ReleaseLock(PRUint32 cid, const char *key) +static PRBool +ipcLockModule_ReleaseLockHelper(PRUint32 cid, const char *key, ipcLockContext *ctx) { printf("$$$ 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) { - // - // 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; - PL_HashTableRemove(gLockTable, key); - } - } - 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; - } - } - } - } + 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; - ipcLockModule_ReleaseLock(cid, (const char *) he->key); + ipcLockModule_ReleaseLockHelper(cid, (const char *) he->key, + (ipcLockContext *) he->value); return HT_ENUMERATE_NEXT; } diff --git a/mozilla/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp b/mozilla/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp index cfd234ab059..5eb8edc639c 100644 --- a/mozilla/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp +++ b/mozilla/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp @@ -97,6 +97,8 @@ tmTransactionService::~tmTransactionService() { if (qmap) delete qmap; } + + IPC_Shutdown(); } ////////////////////////////////////////////////////////////////////////////// @@ -112,12 +114,15 @@ NS_IMPL_ISUPPORTS2(tmTransactionService, NS_IMETHODIMP tmTransactionService::Init(const nsACString & aNamespace) { - // register with the IPC service - ipcService = do_GetService("@mozilla.org/ipc/service;1"); - if (!ipcService) - return NS_ERROR_FAILURE; - if(NS_FAILED(ipcService->SetMessageObserver(kTransModuleID, this))) - return NS_ERROR_FAILURE; + nsresult rv; + + rv = IPC_Init(); + if (NS_FAILED(rv)) + return rv; + + rv = IPC_DefineTarget(kTransModuleID, this); + if (NS_FAILED(rv)) + return rv; // get the lock service lockService = do_GetService("@mozilla.org/ipc/lock-service;1"); @@ -185,6 +190,7 @@ tmTransactionService::Attach(const nsACString & aDomainName, // acquire a lock if neccessary if (aLockingCall) lockService->AcquireLock(joinedQueueName, nsnull, 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 @@ -269,7 +275,8 @@ tmTransactionService::PostTransaction(const nsACString & aDomainName, // ipcIMessageObserver NS_IMETHODIMP -tmTransactionService::OnMessageAvailable(const nsID & aTarget, +tmTransactionService::OnMessageAvailable(const PRUint32 aSenderID, + const nsID & aTarget, const PRUint8 *aData, PRUint32 aDataLength) { @@ -319,13 +326,12 @@ void tmTransactionService::SendMessage(tmTransaction *aTrans, PRBool aSync) { NS_ASSERTION(aTrans, "tmTransactionService::SendMessage called with null transaction"); - NS_ASSERTION(ipcService, "Failed to get the ipcService"); - ipcService->SendMessage(0, - kTransModuleID, - aTrans->GetRawMessage(), - aTrans->GetRawMessageLength(), - aSync); + IPC_SendMessage(0, kTransModuleID, + aTrans->GetRawMessage(), + aTrans->GetRawMessageLength()); + if (aSync) + IPC_WaitMessage(0, kTransModuleID, nsnull, PR_INTERVAL_NO_TIMEOUT); } void diff --git a/mozilla/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h b/mozilla/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h index 9d259946cb8..cd9310feb46 100644 --- a/mozilla/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h +++ b/mozilla/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h @@ -38,7 +38,7 @@ #ifndef _tmTransactionService_H_ #define _tmTransactionService_H_ -#include "ipcIService.h" +#include "ipcdclient.h" #include "ipcILockService.h" #include "ipcIMessageObserver.h" #include "ipcITransactionService.h" @@ -187,7 +187,6 @@ protected: tmVector mQueueMaps; // queue - name - domain mappings tmVector mWaitingMessages; // messages sent before ATTACH_REPLY - nsCOMPtr ipcService; // cache the ipc service nsCOMPtr lockService; // cache the lock service private: diff --git a/mozilla/ipc/ipcd/shared/src/ipcConfig.h b/mozilla/ipc/ipcd/shared/src/ipcConfig.h index 486abb9fe91..8b2155c3cb3 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcConfig.h +++ b/mozilla/ipc/ipcd/shared/src/ipcConfig.h @@ -64,7 +64,7 @@ inline void IPC_GetClientWindowName(PRUint32 pid, char *buf) } #else -#include "prtypes.h" +#include "nscore.h" // // use UNIX domain socket // @@ -79,7 +79,7 @@ inline void IPC_GetClientWindowName(PRUint32 pid, char *buf) #define IPC_MODULES_DIR "ipc/modules" #endif -void IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen); +NS_HIDDEN_(void) IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen); #endif diff --git a/mozilla/ipc/ipcd/shared/src/ipcIDList.h b/mozilla/ipc/ipcd/shared/src/ipcIDList.h index f4eba010932..159a92f4747 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcIDList.h +++ b/mozilla/ipc/ipcd/shared/src/ipcIDList.h @@ -95,8 +95,8 @@ public: } private: - static ipcIDNode *FindNode (ipcIDNode *head, const nsID &id); - static ipcIDNode *FindNodeBefore(ipcIDNode *head, const nsID &id); + static NS_HIDDEN_(ipcIDNode *) FindNode (ipcIDNode *head, const nsID &id); + static NS_HIDDEN_(ipcIDNode *) FindNodeBefore(ipcIDNode *head, const nsID &id); }; #endif // !ipcIDList_h__ diff --git a/mozilla/ipc/ipcd/shared/src/ipcList.h b/mozilla/ipc/ipcd/shared/src/ipcList.h index e93838b424d..3512d0deb5c 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcList.h +++ b/mozilla/ipc/ipcd/shared/src/ipcList.h @@ -161,6 +161,17 @@ public: PRBool IsEmpty() const { return mHead == NULL; } + // + // moves contents of list to another list + // + void MoveTo(ipcList &other) + { + other.mHead = mHead; + other.mTail = mTail; + mHead = NULL; + mTail = NULL; + } + protected: void AdvanceHead() { diff --git a/mozilla/ipc/ipcd/shared/src/ipcLog.h b/mozilla/ipc/ipcd/shared/src/ipcLog.h index 1cd3ad46e0f..8dae934b4d7 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcLog.h +++ b/mozilla/ipc/ipcd/shared/src/ipcLog.h @@ -38,6 +38,7 @@ #ifndef ipcLog_h__ #define ipcLog_h__ +#include "nscore.h" #include "prtypes.h" #ifdef DEBUG @@ -47,8 +48,8 @@ #ifdef IPC_LOGGING extern PRBool ipcLogEnabled; -extern void IPC_InitLog(const char *prefix); -extern void IPC_Log(const char *fmt, ...); +extern NS_HIDDEN_(void) IPC_InitLog(const char *prefix); +extern NS_HIDDEN_(void) IPC_Log(const char *fmt, ...); #define IPC_LOG(_args) \ PR_BEGIN_MACRO \ diff --git a/mozilla/ipc/ipcd/shared/src/ipcMessage.h b/mozilla/ipc/ipcd/shared/src/ipcMessage.h index d9a24c8fc19..405a4b6cbee 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcMessage.h +++ b/mozilla/ipc/ipcd/shared/src/ipcMessage.h @@ -88,26 +88,28 @@ class ipcMessage public: ipcMessage() : mNext(NULL) + , mMetaData(0) , mMsgHdr(NULL) , mMsgOffset(0) , mMsgComplete(PR_FALSE) { } ipcMessage(const nsID &target, const char *data, PRUint32 dataLen) : mNext(NULL) + , mMetaData(0) , mMsgHdr(NULL) , mMsgOffset(0) { Init(target, data, dataLen); } - ~ipcMessage(); + ~ipcMessage() NS_HIDDEN; // // reset message to uninitialized state // - void Reset(); + NS_HIDDEN_(void) Reset(); // // create a copy of this message // - ipcMessage *Clone() const; + NS_HIDDEN_(ipcMessage *) Clone() const; // // initialize message @@ -117,7 +119,7 @@ public: // data - message data (may be null to leave data uninitialized) // dataLen - message data len // - PRStatus Init(const nsID &target, const char *data, PRUint32 dataLen); + NS_HIDDEN_(PRStatus) Init(const nsID &target, const char *data, PRUint32 dataLen); // // copy data into the message's data section, starting from offset. this @@ -128,7 +130,7 @@ public: // data - data to write // dataLen - number of bytes to write // - PRStatus SetData(PRUint32 offset, const char *data, PRUint32 dataLen); + NS_HIDDEN_(PRStatus) SetData(PRUint32 offset, const char *data, PRUint32 dataLen); // // access message flags @@ -161,32 +163,39 @@ public: // data - message data (must not be null) // dataLen - message data length // - PRBool Equals(const nsID &target, const char *data, PRUint32 dataLen) const; - PRBool Equals(const ipcMessage *msg) const; + NS_HIDDEN_(PRBool) Equals(const nsID &target, const char *data, PRUint32 dataLen) const; + NS_HIDDEN_(PRBool) Equals(const ipcMessage *msg) const; // // write the message to a buffer segment; segment need not be large // enough to hold entire message. called repeatedly. // - PRStatus WriteTo(char *buf, - PRUint32 bufLen, - PRUint32 *bytesWritten, - PRBool *complete); + NS_HIDDEN_(PRStatus) WriteTo(char *buf, + PRUint32 bufLen, + PRUint32 *bytesWritten, + PRBool *complete); // // read the message from a buffer segment; segment need not contain // the entire messgae. called repeatedly. // - PRStatus ReadFrom(const char *buf, - PRUint32 bufLen, - PRUint32 *bytesRead, - PRBool *complete); + NS_HIDDEN_(PRStatus) ReadFrom(const char *buf, + PRUint32 bufLen, + PRUint32 *bytesRead, + PRBool *complete); // // a message can be added to a singly-linked list. // class ipcMessage *mNext; + // + // meta data associated with this message object. the owner of the + // ipcMessage object is free to use this field for any purpose. by + // default, it is initialized to 0. + // + PRUint32 mMetaData; + private: ipcMessageHeader *mMsgHdr; diff --git a/mozilla/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp b/mozilla/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp index 48981422036..08753ddb882 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp +++ b/mozilla/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp @@ -43,16 +43,39 @@ ipcMessage_DWORD_STR::ipcMessage_DWORD_STR(const nsID &target, const char *second) { int sLen = strlen(second); - Init(target, NULL, sizeof(first) + sLen + 1); - SetData(0, (char *) &first, sizeof(first)); - SetData(sizeof(first), second, sLen + 1); + Init(target, NULL, 4 + sLen + 1); + SetData(0, (char *) &first, 4); + SetData(4, second, sLen + 1); +} + +ipcMessage_DWORD_DWORD_STR::ipcMessage_DWORD_DWORD_STR(const nsID &target, + PRUint32 first, + PRUint32 second, + const char *third) +{ + int sLen = strlen(third); + Init(target, NULL, 8 + sLen + 1); + SetData(0, (char *) &first, 4); + SetData(4, (char *) &second, 4); + SetData(8, third, sLen + 1); } ipcMessage_DWORD_ID::ipcMessage_DWORD_ID(const nsID &target, PRUint32 first, const nsID &second) { - Init(target, NULL, sizeof(first) + sizeof(nsID)); - SetData(0, (char *) &first, sizeof(first)); - SetData(sizeof(first), (char *) &second, sizeof(nsID)); + Init(target, NULL, 4 + sizeof(nsID)); + SetData(0, (char *) &first, 4); + SetData(4, (char *) &second, sizeof(nsID)); +} + +ipcMessage_DWORD_DWORD_ID::ipcMessage_DWORD_DWORD_ID(const nsID &target, + PRUint32 first, + PRUint32 second, + const nsID &third) +{ + Init(target, NULL, 8 + sizeof(nsID)); + SetData(0, (char *) &first, 4); + SetData(4, (char *) &second, 4); + SetData(8, (char *) &third, sizeof(nsID)); } diff --git a/mozilla/ipc/ipcd/shared/src/ipcMessagePrimitives.h b/mozilla/ipc/ipcd/shared/src/ipcMessagePrimitives.h index cc795c41dbe..235196a909d 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcMessagePrimitives.h +++ b/mozilla/ipc/ipcd/shared/src/ipcMessagePrimitives.h @@ -74,10 +74,65 @@ public: } }; +class ipcMessage_DWORD_DWORD_DWORD : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second, PRUint32 third) + { + PRUint32 data[3] = { first, second, third }; + Init(target, (char *) data, sizeof(data)); + } + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } + + PRUint32 Third() const + { + return ((PRUint32 *) Data())[2]; + } +}; + +class ipcMessage_DWORD_DWORD_DWORD_DWORD : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second, PRUint32 third, PRUint32 fourth) + { + PRUint32 data[4] = { first, second, third, fourth }; + Init(target, (char *) data, sizeof(data)); + } + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } + + PRUint32 Third() const + { + return ((PRUint32 *) Data())[2]; + } + + PRUint32 Fourth() const + { + return ((PRUint32 *) Data())[3]; + } +}; + class ipcMessage_DWORD_STR : public ipcMessage { public: - ipcMessage_DWORD_STR(const nsID &target, PRUint32 first, const char *second); + ipcMessage_DWORD_STR(const nsID &target, PRUint32 first, const char *second) NS_HIDDEN; PRUint32 First() const { @@ -90,10 +145,31 @@ public: } }; +class ipcMessage_DWORD_DWORD_STR : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD_STR(const nsID &target, PRUint32 first, PRUint32 second, const char *second) NS_HIDDEN; + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } + + const char *Third() const + { + return Data() + 2 * sizeof(PRUint32); + } +}; + class ipcMessage_DWORD_ID : public ipcMessage { public: - ipcMessage_DWORD_ID(const nsID &target, PRUint32 first, const nsID &second); + ipcMessage_DWORD_ID(const nsID &target, PRUint32 first, const nsID &second) NS_HIDDEN; PRUint32 First() const { @@ -106,4 +182,25 @@ public: } }; +class ipcMessage_DWORD_DWORD_ID : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD_ID(const nsID &target, PRUint32 first, PRUint32 second, const nsID &third) NS_HIDDEN; + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } + + const nsID &Third() const + { + return * (const nsID *) (Data() + 2 * sizeof(PRUint32)); + } +}; + #endif // !ipcMessagePrimitives_h__ diff --git a/mozilla/ipc/ipcd/shared/src/ipcStringList.h b/mozilla/ipc/ipcd/shared/src/ipcStringList.h index 637a55ad05a..3490c0e05e4 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcStringList.h +++ b/mozilla/ipc/ipcd/shared/src/ipcStringList.h @@ -40,7 +40,7 @@ #include #include "plstr.h" -#include "xpcom-config.h" +#include "nscore.h" #include "ipcList.h" //----------------------------------------------------------------------------- @@ -101,8 +101,8 @@ public: } private: - static ipcStringNode *FindNode (ipcStringNode *head, const char *str); - static ipcStringNode *FindNodeBefore(ipcStringNode *head, const char *str); + static NS_HIDDEN_(ipcStringNode *) FindNode (ipcStringNode *head, const char *str); + static NS_HIDDEN_(ipcStringNode *) FindNodeBefore(ipcStringNode *head, const char *str); }; #endif // !ipcStringList_h__ diff --git a/mozilla/ipc/ipcd/shared/src/ipcm.cpp b/mozilla/ipc/ipcd/shared/src/ipcm.cpp index 6a5b58837ef..7f7ed060498 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcm.cpp +++ b/mozilla/ipc/ipcd/shared/src/ipcm.cpp @@ -37,7 +37,7 @@ #include #include "ipcm.h" -#include "prlog.h" +#include "pratom.h" const nsID IPCM_TARGET = { /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */ @@ -47,6 +47,15 @@ const nsID IPCM_TARGET = {0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50} }; +PRUint32 +IPCM_NewRequestIndex() +{ + static PRInt32 sRequestIndex; + return (PRUint32) PR_AtomicIncrement(&sRequestIndex); +} + +#if 0 + // // MSG_TYPE values // @@ -62,6 +71,7 @@ const PRUint32 ipcmMessageClientDelTarget::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_DEL_T const PRUint32 ipcmMessageQueryClientByName::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME; const PRUint32 ipcmMessageQueryClientInfo::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_INFO; const PRUint32 ipcmMessageForward::MSG_TYPE = IPCM_MSG_TYPE_FORWARD; +const PRUint32 ipcmMessageClientStatus::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_STATUS; // // CLIENT_INFO message @@ -71,6 +81,8 @@ const PRUint32 ipcmMessageForward::MSG_TYPE = IPCM_MSG_TYPE_FORWARD; // +--------------------+--------------------+ // | DWORD : clientID | // +--------------------+--------------------+ +// | DWORD : requestIndex | +// +--------------------+--------------------+ // | WORD : nameStart | WORD : nameCount | // +--------------------+--------------------+ // | WORD : targetStart | WORD : targetCount | @@ -95,18 +107,20 @@ struct ipcmClientInfoHeader { PRUint32 mType; PRUint32 mID; + PRUint32 mRequestIndex; PRUint16 mNameStart; PRUint16 mNameCount; PRUint16 mTargetStart; PRUint16 mTargetCount; }; -ipcmMessageClientInfo::ipcmMessageClientInfo(PRUint32 cID, const char *names[], const nsID *targets[]) +ipcmMessageClientInfo::ipcmMessageClientInfo(PRUint32 cID, PRUint32 rIdx, const char *names[], const nsID *targets[]) { ipcmClientInfoHeader hdr = {0}; hdr.mType = MSG_TYPE; hdr.mID = cID; + hdr.mRequestIndex = rIdx; hdr.mNameStart = sizeof(hdr); PRUint32 i, namesLen = 0; @@ -163,6 +177,13 @@ ipcmMessageClientInfo::ClientID() const return hdr->mID; } +PRUint32 +ipcmMessageClientInfo::RequestIndex() const +{ + ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data(); + return hdr->mRequestIndex; +} + PRUint32 ipcmMessageClientInfo::NameCount() const { @@ -203,6 +224,7 @@ ipcmMessageClientInfo::NextTarget(const nsID *target) const target = NULL; return target; } +#endif // // FORWARD message @@ -218,20 +240,24 @@ ipcmMessageClientInfo::NextTarget(const nsID *target) const // +-------------------------+ // -ipcmMessageForward::ipcmMessageForward(PRUint32 cID, +ipcmMessageForward::ipcmMessageForward(PRUint32 type, + PRUint32 cID, const nsID &target, const char *data, PRUint32 dataLen) { - int len = sizeof(MSG_TYPE) + // MSG_TYPE - sizeof(cID) + // cID - IPC_MSG_HEADER_SIZE + // innerMsgHeader - dataLen; // innerMsgData + int len = sizeof(ipcmMessageHeader) + // IPCM header + sizeof(cID) + // cID + IPC_MSG_HEADER_SIZE + // innerMsgHeader + dataLen; // innerMsgData Init(IPCM_TARGET, NULL, len); - SetData(0, (char *) &MSG_TYPE, sizeof(MSG_TYPE)); - SetData(4, (char *) &cID, sizeof(cID)); + ipcmMessageHeader ipcmHdr = + { type, IPCM_NewRequestIndex() }; + + SetData(0, (char *) &ipcmHdr, sizeof(ipcmHdr)); + SetData(sizeof(ipcmHdr), (char *) &cID, sizeof(cID)); ipcMessageHeader hdr; hdr.mLen = IPC_MSG_HEADER_SIZE + dataLen; @@ -239,7 +265,7 @@ ipcmMessageForward::ipcmMessageForward(PRUint32 cID, hdr.mFlags = 0; hdr.mTarget = target; - SetData(8, (char *) &hdr, IPC_MSG_HEADER_SIZE); + SetData(sizeof(ipcmHdr) + sizeof(cID), (char *) &hdr, IPC_MSG_HEADER_SIZE); if (data) SetInnerData(0, data, dataLen); } @@ -247,31 +273,31 @@ ipcmMessageForward::ipcmMessageForward(PRUint32 cID, void ipcmMessageForward::SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen) { - SetData(8 + IPC_MSG_HEADER_SIZE + offset, data, dataLen); + SetData(sizeof(ipcmMessageHeader) + 4 + IPC_MSG_HEADER_SIZE + offset, data, dataLen); } PRUint32 -ipcmMessageForward::DestClientID() const +ipcmMessageForward::ClientID() const { - return ((PRUint32 *) Data())[1]; + return ((PRUint32 *) Data())[2]; } const nsID & ipcmMessageForward::InnerTarget() const { - ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 8); + ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 12); return hdr->mTarget; } const char * ipcmMessageForward::InnerData() const { - return Data() + 8 + IPC_MSG_HEADER_SIZE; + return Data() + 12 + IPC_MSG_HEADER_SIZE; } PRUint32 ipcmMessageForward::InnerDataLen() const { - ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 8); + ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 12); return hdr->mLen - IPC_MSG_HEADER_SIZE; } diff --git a/mozilla/ipc/ipcd/shared/src/ipcm.h b/mozilla/ipc/ipcd/shared/src/ipcm.h index 12b96560c3b..4f4c59c8426 100644 --- a/mozilla/ipc/ipcd/shared/src/ipcm.h +++ b/mozilla/ipc/ipcd/shared/src/ipcm.h @@ -41,47 +41,291 @@ #include "ipcMessage.h" #include "ipcMessagePrimitives.h" +//----------------------------------------------------------------------------- + // // IPCM (IPC Manager) protocol support // +// The IPCM message target identifier: extern const nsID IPCM_TARGET; -enum { - IPCM_MSG_TYPE_PING, - IPCM_MSG_TYPE_ERROR, - IPCM_MSG_TYPE_CLIENT_HELLO, - IPCM_MSG_TYPE_CLIENT_ID, - IPCM_MSG_TYPE_CLIENT_INFO, - IPCM_MSG_TYPE_CLIENT_ADD_NAME, - IPCM_MSG_TYPE_CLIENT_DEL_NAME, - IPCM_MSG_TYPE_CLIENT_ADD_TARGET, - IPCM_MSG_TYPE_CLIENT_DEL_TARGET, - IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME, - IPCM_MSG_TYPE_QUERY_CLIENT_INFO, - // IPCM_MSG_TYPE_QUERY_MODULE, // check if module exists - IPCM_MSG_TYPE_FORWARD, - IPCM_MSG_TYPE_UNKNOWN // unknown message type +// +// Every IPCM message has the following structure: +// +// +-----------------------------------------+ +// | (ipc message header) | +// +-----------------------------------------+ +// | DWORD : type | +// +-----------------------------------------+ +// | DWORD : requestIndex | +// +-----------------------------------------+ +// . . +// . (payload) . +// . . +// +-----------------------------------------+ +// +// where |type| is an integer uniquely identifying the message. the type is +// composed of a message class identifier and a message number. there are 3 +// message classes: +// +// ACK - acknowledging a request +// REQ - making a request +// PSH - providing unrequested, "pushed" information +// +// The requestIndex field is initialized when a request is made. An +// acknowledgement's requestIndex is equal to that of its corresponding +// request message. This enables the requesting side of the message exchange +// to match acknowledgements to requests. The requestIndex field is ignored +// for PSH messages. +// + +// The IPCM message class is stored in the most significant byte. +#define IPCM_MSG_CLASS_REQ (1 << 24) +#define IPCM_MSG_CLASS_ACK (2 << 24) +#define IPCM_MSG_CLASS_PSH (4 << 24) + +// Requests +#define IPCM_MSG_REQ_PING (IPCM_MSG_CLASS_REQ | 1) +#define IPCM_MSG_REQ_FORWARD (IPCM_MSG_CLASS_REQ | 2) +#define IPCM_MSG_REQ_CLIENT_HELLO (IPCM_MSG_CLASS_REQ | 3) +#define IPCM_MSG_REQ_CLIENT_ADD_NAME (IPCM_MSG_CLASS_REQ | 4) +#define IPCM_MSG_REQ_CLIENT_DEL_NAME (IPCM_MSG_CLASS_REQ | 5) +#define IPCM_MSG_REQ_CLIENT_ADD_TARGET (IPCM_MSG_CLASS_REQ | 6) +#define IPCM_MSG_REQ_CLIENT_DEL_TARGET (IPCM_MSG_CLASS_REQ | 7) +#define IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME (IPCM_MSG_CLASS_REQ | 8) +#define IPCM_MSG_REQ_QUERY_CLIENT_NAMES (IPCM_MSG_CLASS_REQ | 9) // TODO +#define IPCM_MSG_REQ_QUERY_CLIENT_TARGETS (IPCM_MSG_CLASS_REQ | 10) // TODO + +// Acknowledgements +#define IPCM_MSG_ACK_RESULT (IPCM_MSG_CLASS_ACK | 1) +#define IPCM_MSG_ACK_CLIENT_ID (IPCM_MSG_CLASS_ACK | 2) +#define IPCM_MSG_ACK_CLIENT_NAMES (IPCM_MSG_CLASS_ACK | 3) // TODO +#define IPCM_MSG_ACK_CLIENT_TARGETS (IPCM_MSG_CLASS_ACK | 4) // TODO + +// Push messages +#define IPCM_MSG_PSH_CLIENT_STATE (IPCM_MSG_CLASS_PSH | 1) +#define IPCM_MSG_PSH_FORWARD (IPCM_MSG_CLASS_PSH | 2) + +//----------------------------------------------------------------------------- + +// +// IPCM header +// +struct ipcmMessageHeader +{ + PRUint32 mType; + PRUint32 mRequestIndex; }; // // returns IPCM message type. // static inline int -IPCM_GetMsgType(const ipcMessage *msg) +IPCM_GetType(const ipcMessage *msg) { - return ((const ipcMessage_DWORD *) msg)->First(); + return ((const ipcmMessageHeader *) msg->Data())->mType; } // -// NOTE: this file declares some helper classes that simplify construction -// and parsing of IPCM messages. each class subclasses ipcMessage, but -// adds no additional member variables. operator new should be used +// return IPCM message request index. +// +static inline PRUint32 +IPCM_GetRequestIndex(const ipcMessage *msg) +{ + return ((const ipcmMessageHeader *) msg->Data())->mRequestIndex; +} + +// +// return a request index that is unique to this process. +// +NS_HIDDEN_(PRUint32) +IPCM_NewRequestIndex(); + +//----------------------------------------------------------------------------- + +// +// The IPCM protocol is detailed below: +// + +// REQUESTS + +// +// req: IPCM_MSG_REQ_PING +// ack: IPCM_MSG_ACK_RESULT +// +// A PING can be sent from either a client to the daemon, or from the daemon +// to a client. The expected acknowledgement is a RESULT message with a status +// code of 0. +// +// This request message has no payload. +// + +// +// req: IPCM_MSG_REQ_FORWARD +// ack: IPCM_MSG_ACK_RESULT +// +// A FORWARD is sent when a client wishes to send a message to another client. +// The payload of this message is another message that should be forwarded by +// the daemon's IPCM to the specified client. The expected acknowledgment is +// a RESULT message with a status code indicating success or failure. +// +// When the daemon receives a FORWARD message, it creates a PSH_FORWARD message +// and sends that on to the destination client. +// +// This request message has as its payload: +// +// +-----------------------------------------+ +// | DWORD : clientID | +// +-----------------------------------------+ +// | (innerMsgHeader) | +// +-----------------------------------------+ +// | (innerMsgData) | +// +-----------------------------------------+ +// + +// +// req: IPCM_MSG_REQ_CLIENT_HELLO +// ack: IPCM_MSG_REQ_CLIENT_ID IPCM_MSG_REQ_RESULT +// +// A CLIENT_HELLO is sent when a client connects to the IPC daemon. The +// expected acknowledgement is a CLIENT_ID message informing the new client of +// its ClientID. If for some reason the IPC daemon cannot accept the new +// client, it returns a RESULT message with a failure status code. +// +// This request message has no payload. +// + +// +// req: IPCM_MSG_REQ_CLIENT_ADD_NAME +// ack: IPCM_MSG_ACK_RESULT +// +// A CLIENT_ADD_NAME is sent when a client wishes to register an additional +// name for itself. The expected acknowledgement is a RESULT message with a +// status code indicating success or failure. +// +// This request message has as its payload a null-terminated ASCII character +// string indicating the name of the client. +// + +// +// req: IPCM_MSG_REQ_CLIENT_DEL_NAME +// ack: IPCM_MSG_ACK_RESULT +// +// A CLIENT_DEL_NAME is sent when a client wishes to unregister a name that it +// has registered. The expected acknowledgement is a RESULT message with a +// status code indicating success or failure. +// +// This request message has as its payload a null-terminated ASCII character +// string indicating the name of the client. +// + +// +// req: IPCM_MSG_REQ_CLIENT_ADD_TARGET +// ack: IPCM_MSG_ACK_RESULT +// +// A CLIENT_ADD_TARGET is sent when a client wishes to register an additional +// target that it supports. The expected acknowledgement is a RESULT message +// with a status code indicating success or failure. +// +// This request message has as its payload a 128-bit UUID indicating the +// target to add. +// + +// +// req: IPCM_MSG_REQ_CLIENT_DEL_TARGET +// ack: IPCM_MSG_ACK_RESULT +// +// A CLIENT_DEL_TARGET is sent when a client wishes to unregister a target +// that it has registered. The expected acknowledgement is a RESULT message +// with a status code indicating success or failure. +// +// This request message has as its payload a 128-bit UUID indicating the +// target to remove. +// + +// +// req: IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME +// ack: IPCM_MSG_ACK_CLIENT_ID IPCM_MSG_ACK_RESULT +// +// A QUERY_CLIENT_BY_NAME may be sent by a client to discover the client that +// is known by a common name. If more than one client matches the name, then +// only the ID of the more recently registered client is returned. The +// expected acknowledgement is a CLIENT_ID message carrying the ID of the +// corresponding client. If no client matches the given name or if some error +// occurs, then a RESULT message with a failure status code is returned. +// +// This request message has as its payload a null-terminated ASCII character +// string indicating the client name to query. +// + +// ACKNOWLEDGEMENTS + +// +// ack: IPCM_MSG_ACK_RESULT +// +// This acknowledgement is returned to indicate a success or failure status. +// +// The payload consists of a single DWORD value. +// +// Possible status codes are listed below (negative values indicate failure +// codes): +// +#define IPCM_OK 0 // success: generic +#define IPCM_ERROR_GENERIC -1 // failure: generic +#define IPCM_ERROR_NO_CLIENT -2 // failure: client does not exist + +// +// ack: IPCM_MSG_ACK_CLIENT_ID +// +// This acknowledgement is returned to specify a client ID. +// +// The payload consists of a single DWORD value. +// + +// PUSH MESSAGES + +// +// psh: ICPM_MSG_PSH_CLIENT_STATE +// +// This message is sent to clients to indicate the status of other clients. +// +// The payload consists of: +// +// +-----------------------------------------+ +// | DWORD : clientID | +// +-----------------------------------------+ +// | DWORD : clientState | +// +-----------------------------------------+ +// +// where, clientState is one of the following values indicating whether the +// client has recently connected (up) or disconnected (down): +// +#define IPCM_CLIENT_STATE_UP 1 +#define IPCM_CLIENT_STATE_DOWN 2 + +// +// psh: IPCM_MSG_PSH_FORWARD +// +// This message is sent by the daemon to a client on behalf of another client. +// The recipient is expected to unpack the contained message and process it. +// +// The payload of this message matches the payload of IPCM_MSG_REQ_FORWARD, +// with the exception that the clientID field is set to the clientID of the +// sender of the IPCM_MSG_REQ_FORWARD message. +// + +//----------------------------------------------------------------------------- + +// +// NOTE: This file declares some helper classes that simplify constructing +// and parsing IPCM messages. Each class subclasses ipcMessage, but +// adds no additional member variables. |operator new| should be used // to allocate one of the IPCM helper classes, e.g.: // // ipcMessage *msg = new ipcmMessageClientHello("foo"); // -// given an arbitrary ipcMessage, it can be parsed using logic similar +// Given an arbitrary ipcMessage, it can be parsed using logic similar // to the following: // // void func(const ipcMessage *unknown) @@ -94,229 +338,162 @@ IPCM_GetMsgType(const ipcMessage *msg) // } // } // -// in other words, these classes are very very lightweight. -// -// -// IPCM_MSG_TYPE_PING -// -// this message may be sent from either the client or the daemon. -// if the daemon receives this message, then it will respond by -// sending back a PING to the client. -// -class ipcmMessagePing : public ipcMessage_DWORD +// REQUESTS + +class ipcmMessagePing : public ipcMessage_DWORD_DWORD { public: - static const PRUint32 MSG_TYPE; - ipcmMessagePing() - : ipcMessage_DWORD(IPCM_TARGET, MSG_TYPE) {} + : ipcMessage_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_REQ_PING, + IPCM_NewRequestIndex()) {} }; -// -// IPCM_MSG_TYPE_ERROR -// -// this message may be sent from the daemon in place of an expected -// result. e.g., if a query fails, the daemon will send an error -// message to indicate the failure. -// -class ipcmMessageError : public ipcMessage_DWORD_DWORD -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageError(PRUint32 reason) - : ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, reason) {} - - PRUint32 Reason() const { return Second(); } -}; - -enum { - IPCM_ERROR_CLIENT_NOT_FOUND = 1 -}; - -// -// IPCM_MSG_TYPE_CLIENT_HELLO -// -// this message is always the first message sent from a client to register -// itself with the daemon. the daemon responds to this message by sending -// the client a CLIENT_ID message informing the client of its client ID. -// -// XXX may want to pass other information here. -// -class ipcmMessageClientHello : public ipcMessage_DWORD -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageClientHello() - : ipcMessage_DWORD(IPCM_TARGET, MSG_TYPE) {} -}; - -// -// IPCM_MSG_TYPE_CLIENT_ID -// -// this message is sent from the daemon to identify a client's ID. -// -class ipcmMessageClientID : public ipcMessage_DWORD_DWORD -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageClientID(PRUint32 clientID) - : ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, clientID) {} - - PRUint32 ClientID() const { return Second(); } -}; - -// -// IPCM_MSG_TYPE_CLIENT_INFO -// -// this message is sent from the daemon to provide the list of names -// and targets for a particular client. -// -class ipcmMessageClientInfo : public ipcMessage -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageClientInfo(PRUint32 clientID, const char **names, const nsID **targets); - - PRUint32 ClientID() const; - PRUint32 NameCount() const; - PRUint32 TargetCount() const; - - const char *NextName(const char *name) const; - const nsID *NextTarget(const nsID *target) const; -}; - -// -// IPCM_MSG_TYPE_CLIENT_ADD_NAME -// -class ipcmMessageClientAddName : public ipcMessage_DWORD_STR -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageClientAddName(const char *name) - : ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {} - - const char *Name() const { return Second(); } -}; - -// -// IPCM_MSG_TYPE_CLIENT_DEL_NAME -// -class ipcmMessageClientDelName : public ipcMessage_DWORD_STR -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageClientDelName(const char *name) - : ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {} - - const char *Name() const { return Second(); } -}; - -// -// IPCM_MSG_TYPE_CLIENT_ADD_TARGET -// -class ipcmMessageClientAddTarget : public ipcMessage_DWORD_ID -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageClientAddTarget(const nsID &target) - : ipcMessage_DWORD_ID(IPCM_TARGET, MSG_TYPE, target) {} - - const nsID &Target() const { return Second(); } -}; - -// -// IPCM_MSG_TYPE_CLIENT_DEL_TARGET -// -class ipcmMessageClientDelTarget : public ipcMessage_DWORD_ID -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageClientDelTarget(const nsID &target) - : ipcMessage_DWORD_ID(IPCM_TARGET, MSG_TYPE, target) {} - - const nsID &Target() const { return Second(); } -}; - -// -// IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME -// -// this message is sent from a client to the daemon to request the ID of the -// client corresponding to the given name. in response the daemon will either -// send a CLIENT_ID or an ERROR message. -// -class ipcmMessageQueryClientByName : public ipcMessage_DWORD_STR -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageQueryClientByName(const char *name) - : ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {} - - const char *Name() const { return Second(); } -}; - -// -// IPCM_MSG_TYPE_QUERY_CLIENT_INFO -// -// this message is sent from a client to the daemon to request complete -// information about the client corresponding to the given client ID. in -// response the daemon will either send a CLIENT_INFO or an ERROR message. -// -class ipcmMessageQueryClientInfo : public ipcMessage_DWORD_DWORD -{ -public: - static const PRUint32 MSG_TYPE; - - ipcmMessageQueryClientInfo(PRUint32 clientID) - : ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, clientID) {} - - PRUint32 ClientID() const { return Second(); } -}; - -// -// IPCM_MSG_TYPE_FORWARD -// -// this message is only sent from the client to the daemon. the daemon -// will forward the contained message to the specified client. there -// is no guarantee that the message will be forwarded, and no error will -// be sent to the sender on failure. -// class ipcmMessageForward : public ipcMessage { public: - static const PRUint32 MSG_TYPE; - - // - // params: - // clientID - the client to which the message should be forwarded - // target - the message target - // data - the message data - // dataLen - the message data length - // - ipcmMessageForward(PRUint32 clientID, + // @param type the type of this message: IPCM_MSG_{REQ,PSH}_FORWARD + // @param clientID the client id of the sender or receiver + // @param target the message target + // @param data the message data + // @param dataLen the message data length + ipcmMessageForward(PRUint32 type, + PRUint32 clientID, const nsID &target, const char *data, - PRUint32 dataLen); + PRUint32 dataLen) NS_HIDDEN; - // // set inner message data, constrained to the data length passed // to this class's constructor. - // - void SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen); + NS_HIDDEN_(void) SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen); - PRUint32 DestClientID() const; - const nsID &InnerTarget() const; - const char *InnerData() const; - PRUint32 InnerDataLen() const; + NS_HIDDEN_(PRUint32) ClientID() const; + NS_HIDDEN_(const nsID &) InnerTarget() const; + NS_HIDDEN_(const char *) InnerData() const; + NS_HIDDEN_(PRUint32) InnerDataLen() const; +}; + +class ipcmMessageClientHello : public ipcMessage_DWORD_DWORD +{ +public: + ipcmMessageClientHello() + : ipcMessage_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_HELLO, + IPCM_NewRequestIndex()) {} +}; + +class ipcmMessageClientAddName : public ipcMessage_DWORD_DWORD_STR +{ +public: + ipcmMessageClientAddName(const char *name) + : ipcMessage_DWORD_DWORD_STR( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_ADD_NAME, + IPCM_NewRequestIndex(), + name) {} + + const char *Name() const { return Third(); } +}; + +class ipcmMessageClientDelName : public ipcMessage_DWORD_DWORD_STR +{ +public: + ipcmMessageClientDelName(const char *name) + : ipcMessage_DWORD_DWORD_STR( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_DEL_NAME, + IPCM_NewRequestIndex(), + name) {} + + const char *Name() const { return Third(); } +}; + +class ipcmMessageClientAddTarget : public ipcMessage_DWORD_DWORD_ID +{ +public: + ipcmMessageClientAddTarget(const nsID &target) + : ipcMessage_DWORD_DWORD_ID( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_ADD_TARGET, + IPCM_NewRequestIndex(), + target) {} + + const nsID &Target() const { return Third(); } +}; + +class ipcmMessageClientDelTarget : public ipcMessage_DWORD_DWORD_ID +{ +public: + ipcmMessageClientDelTarget(const nsID &target) + : ipcMessage_DWORD_DWORD_ID( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_ADD_TARGET, + IPCM_NewRequestIndex(), + target) {} + + const nsID &Target() const { return Third(); } +}; + +class ipcmMessageQueryClientByName : public ipcMessage_DWORD_DWORD_STR +{ +public: + ipcmMessageQueryClientByName(const char *name) + : ipcMessage_DWORD_DWORD_STR( + IPCM_TARGET, + IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME, + IPCM_NewRequestIndex(), + name) {} + + const char *Name() const { return Third(); } + PRUint32 RequestIndex() const { return Second(); } +}; + +// ACKNOWLEDGEMENTS + +class ipcmMessageResult : public ipcMessage_DWORD_DWORD_DWORD +{ +public: + ipcmMessageResult(PRUint32 requestIndex, PRInt32 status) + : ipcMessage_DWORD_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_ACK_RESULT, + requestIndex, + (PRUint32) status) {} + + PRInt32 Status() const { return (PRInt32) Third(); } +}; + +class ipcmMessageClientID : public ipcMessage_DWORD_DWORD_DWORD +{ +public: + ipcmMessageClientID(PRUint32 requestIndex, PRUint32 clientID) + : ipcMessage_DWORD_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_ACK_CLIENT_ID, + requestIndex, + clientID) {} + + PRUint32 ClientID() const { return Third(); } +}; + +// PUSH MESSAGES + +class ipcmMessageClientState : public ipcMessage_DWORD_DWORD_DWORD_DWORD +{ +public: + ipcmMessageClientState(PRUint32 clientID, PRUint32 clientStatus) + : ipcMessage_DWORD_DWORD_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_PSH_CLIENT_STATE, + 0, + clientID, + clientStatus) {} + + PRUint32 ClientID() const { return Third(); } + PRUint32 ClientState() const { return Fourth(); } }; #endif // !ipcm_h__ diff --git a/mozilla/ipc/ipcd/test/TestIPC.cpp b/mozilla/ipc/ipcd/test/TestIPC.cpp index 44de0440775..ab03e05ce50 100644 --- a/mozilla/ipc/ipcd/test/TestIPC.cpp +++ b/mozilla/ipc/ipcd/test/TestIPC.cpp @@ -40,6 +40,8 @@ #include "ipcIClientQueryHandler.h" #include "ipcILockService.h" #include "ipcILockNotify.h" +#include "ipcCID.h" +#include "ipcLockCID.h" #include "nsIEventQueueService.h" #include "nsIServiceManager.h" @@ -75,7 +77,6 @@ static const nsID kTestTargetID = 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 ipcILockService *gIpcLockServ = nsnull; @@ -84,8 +85,19 @@ SendMsg(ipcIService *ipc, PRUint32 cID, const nsID &target, const char *data, PR { printf("*** sending message: [to-client=%u dataLen=%u]\n", cID, dataLen); - ipc->SendMessage(cID, target, (const PRUint8 *) data, dataLen, sync); -// gMsgCount++; + nsresult rv; + + rv = ipc->SendMessage(cID, target, (const PRUint8 *) data, dataLen); + if (NS_FAILED(rv)) { + printf("*** sending message failed: rv=%x\n", rv); + return; + } + + if (sync) { + rv = ipc->WaitMessage(cID, target, nsnull, PR_UINT32_MAX); + if (NS_FAILED(rv)) + printf("*** waiting for message failed: rv=%x\n", rv); + } } //----------------------------------------------------------------------------- @@ -95,25 +107,19 @@ class myIpcMessageObserver : public ipcIMessageObserver public: NS_DECL_ISUPPORTS NS_DECL_IPCIMESSAGEOBSERVER - - myIpcMessageObserver() {} }; - NS_IMPL_ISUPPORTS1(myIpcMessageObserver, ipcIMessageObserver) NS_IMETHODIMP -myIpcMessageObserver::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUint32 dataLen) +myIpcMessageObserver::OnMessageAvailable(PRUint32 sender, const nsID &target, const PRUint8 *data, PRUint32 dataLen) { - printf("*** got message: [%s]\n", (const char *) data); - -// if (--gMsgCount == 0) -// gKeepRunning = PR_FALSE; - + printf("*** got message: [sender=%u data=%s]\n", sender, (const char *) data); return NS_OK; } //----------------------------------------------------------------------------- +#if 0 class myIpcClientQueryHandler : public ipcIClientQueryHandler { public: @@ -160,6 +166,7 @@ myIpcClientQueryHandler::OnQueryComplete(PRUint32 aQueryID, return NS_OK; } +#endif //----------------------------------------------------------------------------- @@ -205,16 +212,17 @@ int main(int argc, char **argv) rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); RETURN_IF_FAILED(rv, "GetThreadEventQueue"); + printf("*** getting ipc service\n"); nsCOMPtr ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv)); RETURN_IF_FAILED(rv, "do_GetService(ipcServ)"); NS_ADDREF(gIpcServ = ipcServ); if (argc > 1) { printf("*** using client name [%s]\n", argv[1]); - gIpcServ->AddClientName(argv[1]); + gIpcServ->AddName(argv[1]); } - ipcServ->SetMessageObserver(kTestTargetID, new myIpcMessageObserver()); + ipcServ->DefineTarget(kTestTargetID, new myIpcMessageObserver()); const char data[] = "01 this is a really long message.\n" @@ -279,9 +287,18 @@ int main(int argc, char **argv) "60 this is a really long message.\n"; SendMsg(ipcServ, 0, kTestTargetID, data, sizeof(data), PR_TRUE); - PRUint32 queryID; - nsCOMPtr handler(new myIpcClientQueryHandler()); - ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID); +// PRUint32 queryID; +// nsCOMPtr handler(new myIpcClientQueryHandler()); +// ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID); + + PRUint32 foopyID; + nsresult foopyRv = ipcServ->ResolveClientName("foopy", &foopyID); + printf("*** query for 'foopy' returned [rv=%x id=%u]\n", foopyRv, foopyID); + + if (NS_SUCCEEDED(foopyRv)) { + const char hello[] = "hello friend!"; + SendMsg(ipcServ, foopyID, kTestTargetID, hello, sizeof(hello)); + } // // test lock service