patch for bug 242248 "IPC synchronous message support needs to be reworked" (not yet used for anything)

This commit is contained in:
darin%meer.net 2004-05-03 18:40:33 +00:00
parent 5a1e4899be
commit 3518a0fd5b
36 changed files with 2382 additions and 976 deletions

View File

@ -45,11 +45,16 @@ include $(DEPTH)/config/autoconf.mk
MODULE = ipcd MODULE = ipcd
EXPORTS = \
ipcdclient.h \
ipcCID.h \
$(NULL)
XPIDLSRCS = \ XPIDLSRCS = \
ipcIService.idl \ ipcIService.idl \
ipcIMessageObserver.idl \ ipcIMessageObserver.idl \
ipcIClientObserver.idl \ ipcIClientObserver.idl \
ipcIClientQueryHandler.idl \ ipcIClientInfo.idl \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -46,6 +46,6 @@ interface ipcIClientObserver : nsISupports
const unsigned long CLIENT_UP = 1; const unsigned long CLIENT_UP = 1;
const unsigned long CLIENT_DOWN = 2; const unsigned long CLIENT_DOWN = 2;
void onClientStatus(in unsigned long aClientID, void onClientStateChange(in unsigned long aClientID,
in unsigned long aClientStatus); in unsigned long aClientState);
}; };

View File

@ -44,6 +44,9 @@
interface ipcIMessageObserver : nsISupports 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 * @param aTarget
* the target of the message, corresponding to the target this * the target of the message, corresponding to the target this
* observer was registered under. this parameter is passed to allow * observer was registered under. this parameter is passed to allow
@ -53,7 +56,8 @@ interface ipcIMessageObserver : nsISupports
* @param aDataLen * @param aDataLen
* the data length of the message. * 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)] [array, const, size_is(aDataLen)]
in octet aData, in octet aData,
in unsigned long aDataLen); in unsigned long aDataLen);

View File

@ -39,7 +39,6 @@
interface ipcIMessageObserver; interface ipcIMessageObserver;
interface ipcIClientObserver; interface ipcIClientObserver;
interface ipcIClientQueryHandler;
/** /**
* ipcIService * ipcIService
@ -82,7 +81,7 @@ interface ipcIService : nsISupports
* *
* @throws NS_ERROR_NOT_AVAILABLE if no connection to the IPC daemon. * @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 * 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. * XXX An IPC client name resembles a XPCOM contract ID.
*/ */
void addClientName(in string aName); void addName(in string aName);
void removeClientName(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 * client query methods
*/ */
/** /**
* query info about a particular client given its client name. the * resolve the given client name to the id of a connected client. this
* observer's onClientInfo method is called with the result of the lookup, * involves a round trip to the daemon, and as a result the calling thread
* or if there is no client matching the given name, the observer's * may block on this function call while waiting for the daemon to respond.
* 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.
*/ */
unsigned long queryClientByName(in string aName, unsigned long resolveClientName(in string aName);
in ipcIClientQueryHandler aHandler,
in boolean aSync);
/** /**
* query info about a particular client given its client ID. the observer's * tests whether a particular client is connected to the IPC daemon.
* 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.
*/ */
unsigned long queryClientByID(in unsigned long aClientID, boolean clientExists(in unsigned long aClientID);
in ipcIClientQueryHandler aHandler,
in boolean aSync);
/**
* 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. // 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 * the message observer to receive incoming messages for the
* specified target. pass null to remove the existing observer. * 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. * send message asynchronously to a client or a module in the IPC daemon.
@ -192,33 +162,50 @@ interface ipcIService : nsISupports
* the message data. * the message data.
* @param aDataLen * @param aDataLen
* the message length. * 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, in nsIDRef aTarget,
[array, const, size_is(aDataLen)] [array, const, size_is(aDataLen)]
in octet aData, in octet aData,
in unsigned long aDataLen, in unsigned long aDataLen);
in boolean aSync);
/**
* 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++ %{C++
// singleton implementing ipcIService // category and observer event defines (XXX not yet implemented)
#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
#define IPC_SERVICE_STARTUP_CATEGORY "ipc-startup-category" #define IPC_SERVICE_STARTUP_CATEGORY "ipc-startup-category"
#define IPC_SERVICE_STARTUP_TOPIC "ipc-startup" #define IPC_SERVICE_STARTUP_TOPIC "ipc-startup"
#define IPC_SERVICE_SHUTDOWN_TOPIC "ipc-shutdown" #define IPC_SERVICE_SHUTDOWN_TOPIC "ipc-shutdown"

View File

@ -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 <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef ipcdclient_h__
#define ipcdclient_h__
/*****************************************************************************
* This file provides a client-side API to the IPC daemon.
*
* This API can be used to communicate with other clients of the IPC daemon
* as well as modules running inside the IPC daemon.
*
* This API is meant to be used only on the application's main thread. It is
* assumed that callbacks can be dispatched via the main thread's event queue.
*/
#include "nscore.h"
#include "nsID.h"
#include "nsError.h"
#include "ipcIMessageObserver.h"
#include "ipcIClientObserver.h"
/* This API is only provided for the extensions compiled into the IPCDC
* library, hence this API is hidden in the final DSO. */
#define IPC_METHOD NS_HIDDEN_(nsresult)
/* This value can be used to represent the client id of any client connected
* to the IPC daemon. */
#define IPC_SENDER_ANY PR_UINT32_MAX
/* This error code can only be returned by OnMessageAvailable, when called by
* IPC_WaitMessage. See IPC_WaitMessage for a description of how this error
* code may be used. */
#define IPC_WAIT_NEXT_MESSAGE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 10)
/* 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__ */

View File

@ -55,8 +55,8 @@ REQUIRES = \
$(NULL) $(NULL)
CPPSRCS = \ CPPSRCS = \
ipcdclient.cpp \
ipcService.cpp \ ipcService.cpp \
ipcTransport.cpp \
ipcModuleFactory.cpp \ ipcModuleFactory.cpp \
$(NULL) $(NULL)

View File

@ -42,6 +42,9 @@
class ipcMessage; class ipcMessage;
#define IPC_METHOD_PRIVATE_(type) NS_HIDDEN_(type)
#define IPC_METHOD_PRIVATE IPC_METHOD_PRIVATE_(nsresult)
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Platform specific IPC connection API. /* Platform specific IPC connection API.
*/ */
@ -57,7 +60,7 @@ class ipcMessage;
* *
* NOTE: This function must be called on the main thread. * 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 * IPC_Disconnect
@ -68,7 +71,7 @@ nsresult IPC_Connect(const char *daemonPath);
* *
* NOTE: This function must be called on the main thread. * NOTE: This function must be called on the main thread.
*/ */
nsresult IPC_Disconnect(); IPC_METHOD_PRIVATE IPC_Disconnect();
/** /**
* IPC_SendMsg * IPC_SendMsg
@ -82,7 +85,7 @@ nsresult IPC_Disconnect();
* *
* NOTE: This function may be called on any thread. * 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. /* Cross-platform IPC connection methods.
@ -99,7 +102,7 @@ nsresult IPC_SendMsg(ipcMessage *msg);
* @param daemonPath * @param daemonPath
* Specifies the path to the IPC daemon executable. * 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). /* 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 * 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. * 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 * IPC_OnMessageAvailable
@ -124,6 +127,6 @@ void IPC_OnConnectionEnd(nsresult error);
* daemon. The ipcMessage object, |msg|, must be deleted by the implementation * daemon. The ipcMessage object, |msg|, must be deleted by the implementation
* of IPC_OnMessageAvailable when the object is no longer needed. * 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__ #endif // ipcConnection_h__

View File

@ -40,6 +40,8 @@
#include "nsICategoryManager.h" #include "nsICategoryManager.h"
#include "ipcService.h" #include "ipcService.h"
#include "ipcConfig.h" #include "ipcConfig.h"
#include "ipcCID.h"
#include "ipcLockCID.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Define the contructor function for the objects // Define the contructor function for the objects
@ -93,6 +95,45 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcLockService, Init)
#include "tmTransactionService.h" #include "tmTransactionService.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService) 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<nsICategoryManager> catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
if (catman) {
nsXPIDLCString prevEntry;
catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcDConnectService",
IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE, PR_TRUE,
getter_Copies(prevEntry));
}
return NS_OK;
}
NS_METHOD
ipcDConnectServiceUnregisterProc(nsIComponentManager *aCompMgr,
nsIFile *aPath,
const char *registryLocation,
const nsModuleComponentInfo *info)
{
nsCOMPtr<nsICategoryManager> catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID));
if (catman)
catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID,
IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE);
return NS_OK;
}
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Define a table of CIDs implemented by this module along with other // Define a table of CIDs implemented by this module along with other
// information like the function to create an instance, contractid, and // information like the function to create an instance, contractid, and
@ -118,6 +159,12 @@ static const nsModuleComponentInfo components[] = {
IPC_TRANSACTIONSERVICE_CID, IPC_TRANSACTIONSERVICE_CID,
IPC_TRANSACTIONSERVICE_CONTRACTID, IPC_TRANSACTIONSERVICE_CONTRACTID,
tmTransactionServiceConstructor }, tmTransactionServiceConstructor },
#if 0
{ IPC_DCONNECTSERVICE_CLASSNAME,
IPC_DCONNECTSERVICE_CID,
IPC_DCONNECTSERVICE_CONTRACTID,
ipcDConnectServiceConstructor },
#endif
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -14,9 +14,8 @@
* *
* The Original Code is Mozilla IPC. * The Original Code is Mozilla IPC.
* *
* The Initial Developer of the Original Code is * The Initial Developer of the Original Code is IBM Corporation.
* Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 2004
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
@ -36,472 +35,69 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#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 "ipcService.h"
#include "ipcMessageUtils.h"
#include "ipcm.h"
#include "ipcIMessageObserver.h" NS_IMPL_ISUPPORTS1(ipcService, ipcIService)
#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<ipcIClientQueryHandler> 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<nsIObserverService> 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<nsIObserverService> 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_IMETHODIMP NS_IMETHODIMP
ipcService::GetClientID(PRUint32 *clientID) ipcService::GetID(PRUint32 *aID)
{ {
NS_ENSURE_TRUE(mClientID != 0, NS_ERROR_NOT_INITIALIZED); return IPC_GetID(aID);
*clientID = mClientID;
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
ipcService::AddClientName(const char *name) ipcService::AddName(const char *aName)
{ {
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); return IPC_AddName(aName);
ipcMessage *msg = new ipcmMessageClientAddName(name);
if (!msg)
return NS_ERROR_OUT_OF_MEMORY;
return mTransport->SendMsg(msg);
} }
NS_IMETHODIMP NS_IMETHODIMP
ipcService::RemoveClientName(const char *name) ipcService::RemoveName(const char *aName)
{ {
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); return IPC_RemoveName(aName);
ipcMessage *msg = new ipcmMessageClientDelName(name);
if (!msg)
return NS_ERROR_OUT_OF_MEMORY;
return mTransport->SendMsg(msg);
} }
NS_IMETHODIMP NS_IMETHODIMP
ipcService::QueryClientByName(const char *name, ipcService::AddClientObserver(ipcIClientObserver *aObserver)
ipcIClientQueryHandler *handler,
PRBool sync,
PRUint32 *queryID)
{ {
if (!mTransport) return IPC_AddClientObserver(aObserver);
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;
} }
NS_IMETHODIMP NS_IMETHODIMP
ipcService::QueryClientByID(PRUint32 clientID, ipcService::RemoveClientObserver(ipcIClientObserver *aObserver)
ipcIClientQueryHandler *handler,
PRBool sync,
PRUint32 *queryID)
{ {
if (!mTransport) return IPC_RemoveClientObserver(aObserver);
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;
} }
NS_IMETHODIMP NS_IMETHODIMP
ipcService::CancelQuery(PRUint32 queryID) ipcService::ResolveClientName(const char *aName, PRUint32 *aID)
{ {
ipcClientQuery *query = mQueryQ.First(); return IPC_ResolveClientName(aName, aID);
while (query) {
if (query->QueryID() == queryID) {
query->OnQueryComplete(NS_ERROR_ABORT, NULL);
break;
}
query = query->mNext;
}
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
ipcService::SetClientObserver(ipcIClientObserver *observer) ipcService::ClientExists(PRUint32 aClientID, PRBool *aResult)
{ {
return NS_ERROR_NOT_IMPLEMENTED; return IPC_ClientExists(aClientID, aResult);
} }
NS_IMETHODIMP NS_IMETHODIMP
ipcService::SetMessageObserver(const nsID &target, ipcIMessageObserver *observer) ipcService::DefineTarget(const nsID &aTarget, ipcIMessageObserver *aObserver)
{ {
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); return IPC_DefineTarget(aTarget, aObserver);
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;
} }
NS_IMETHODIMP NS_IMETHODIMP
ipcService::SendMessage(PRUint32 clientID, ipcService::SendMessage(PRUint32 aReceiverID, const nsID &aTarget,
const nsID &target, const PRUint8 *aData, PRUint32 aDataLen)
const PRUint8 *data,
PRUint32 dataLen,
PRBool sync)
{ {
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED); return IPC_SendMessage(aReceiverID, aTarget, aData, aDataLen);
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);
} }
//-----------------------------------------------------------------------------
// nsIObserver impl
//-----------------------------------------------------------------------------
NS_IMETHODIMP 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) return IPC_WaitMessage(aSenderID, aTarget, aObserver, PR_MillisecondsToInterval(aTimeout));
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());
}
} }

View File

@ -38,52 +38,19 @@
#ifndef ipcService_h__ #ifndef ipcService_h__
#define ipcService_h__ #define ipcService_h__
#include "nsHashtable.h"
#include "nsAutoPtr.h"
#include "plevent.h"
#include "ipcIService.h" #include "ipcIService.h"
#include "ipcTransport.h" #include "ipcdclient.h"
#include "ipcList.h"
#include "ipcMessage.h"
#include "ipcMessageQ.h"
#include "ipcm.h"
typedef ipcList<class ipcClientQuery> ipcClientQueryQ;
//----------------------------------------------------------------------------
// ipcService
//----------------------------------------------------------------------------
class ipcService : public ipcIService class ipcService : public ipcIService
, public ipcTransportObserver
, public nsIObserver
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_IPCISERVICE NS_DECL_IPCISERVICE
NS_DECL_NSIOBSERVER
ipcService(); NS_HIDDEN_(nsresult) Init() { return IPC_Init(); }
virtual ~ipcService();
nsresult Init();
void Shutdown();
// ipcTransportObserver:
void OnConnectionLost();
void OnMessageAvailable(const ipcMessage *);
private: private:
nsresult ErrorAccordingToIPCM(PRUint32 err); ~ipcService() { IPC_Shutdown(); }
void OnIPCMClientID(const ipcmMessageClientID *);
void OnIPCMClientInfo(const ipcmMessageClientInfo *);
void OnIPCMError(const ipcmMessageError *);
nsHashtable mObserverDB;
nsRefPtr<ipcTransport> mTransport;
ipcClientQueryQ mQueryQ;
PRUint32 mClientID;
}; };
#endif // !ipcService_h__ #endif // !defined( ipcService_h__ )

View File

@ -126,7 +126,7 @@ end:
if (attr) if (attr)
PR_DestroyProcessAttr(attr); PR_DestroyProcessAttr(attr);
return rv; return rv;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// ipcTransport // ipcTransport

File diff suppressed because it is too large Load Diff

View File

@ -107,7 +107,7 @@ struct ipcCommandModule
{ {
LOG(("got PING\n")); LOG(("got PING\n"));
IPC_SendMsg(client, new ipcmMessagePing()); IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK));
} }
static void static void
@ -115,7 +115,7 @@ struct ipcCommandModule
{ {
LOG(("got CLIENT_HELLO\n")); 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 // NOTE: it would almost make sense for this notification to live
@ -136,6 +136,9 @@ struct ipcCommandModule
const char *name = msg->Name(); const char *name = msg->Name();
if (name) if (name)
client->AddName(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 static void
@ -147,6 +150,9 @@ struct ipcCommandModule
const char *name = msg->Name(); const char *name = msg->Name();
if (name) if (name)
client->DelName(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 static void
@ -156,6 +162,9 @@ struct ipcCommandModule
ipcMessageCast<ipcmMessageClientAddTarget> msg(rawMsg); ipcMessageCast<ipcmMessageClientAddTarget> msg(rawMsg);
client->AddTarget(msg->Target()); 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 static void
@ -165,6 +174,9 @@ struct ipcCommandModule
ipcMessageCast<ipcmMessageClientDelTarget> msg(rawMsg); ipcMessageCast<ipcmMessageClientDelTarget> msg(rawMsg);
client->DelTarget(msg->Target()); 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 static void
@ -172,18 +184,22 @@ struct ipcCommandModule
{ {
LOG(("got QUERY_CLIENT_BY_NAME\n")); LOG(("got QUERY_CLIENT_BY_NAME\n"));
PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg);
ipcMessageCast<ipcmMessageQueryClientByName> msg(rawMsg); ipcMessageCast<ipcmMessageQueryClientByName> msg(rawMsg);
ipcClient *result = IPC_GetClientByName(msg->Name()); ipcClient *result = IPC_GetClientByName(msg->Name());
if (result) { if (result) {
LOG((" client exists w/ ID = %u\n", result->ID())); 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 { else {
LOG((" client does not exist\n")); 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 static void
OnQueryClientInfo(ipcClient *client, const ipcMessage *rawMsg) OnQueryClientInfo(ipcClient *client, const ipcMessage *rawMsg)
{ {
@ -196,6 +212,7 @@ struct ipcCommandModule
nsID **targets = BuildIDArray(result->Targets()); nsID **targets = BuildIDArray(result->Targets());
IPC_SendMsg(client, new ipcmMessageClientInfo(result->ID(), IPC_SendMsg(client, new ipcmMessageClientInfo(result->ID(),
msg->RequestIndex(),
(const char **) names, (const char **) names,
(const nsID **) targets)); (const nsID **) targets));
@ -204,9 +221,10 @@ struct ipcCommandModule
} }
else { else {
LOG((" client does not exist\n")); 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 static void
OnForward(ipcClient *client, const ipcMessage *rawMsg) OnForward(ipcClient *client, const ipcMessage *rawMsg)
@ -215,14 +233,20 @@ struct ipcCommandModule
ipcMessageCast<ipcmMessageForward> msg(rawMsg); ipcMessageCast<ipcmMessageForward> msg(rawMsg);
ipcClient *dest = IPC_GetClientByID(msg->DestClientID()); ipcClient *dest = IPC_GetClientByID(msg->ClientID());
if (!dest) { if (!dest) {
LOG((" destination client not found!\n")); LOG((" destination client not found!\n"));
IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_ERROR_NO_CLIENT));
return; return;
} }
ipcMessage *newMsg = new ipcMessage(msg->InnerTarget(), // inform client that its message will be forwarded
msg->InnerData(), IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK));
msg->InnerDataLen());
ipcMessage *newMsg = new ipcmMessageForward(IPCM_MSG_PSH_FORWARD,
client->ID(),
msg->InnerTarget(),
msg->InnerData(),
msg->InnerDataLen());
IPC_SendMsg(dest, newMsg); IPC_SendMsg(dest, newMsg);
} }
}; };
@ -233,26 +257,29 @@ IPCM_HandleMsg(ipcClient *client, const ipcMessage *rawMsg)
static ipcCommandModule::MsgHandler handlers[] = static ipcCommandModule::MsgHandler handlers[] =
{ {
ipcCommandModule::OnPing, ipcCommandModule::OnPing,
NULL, // ERROR ipcCommandModule::OnForward,
ipcCommandModule::OnClientHello, ipcCommandModule::OnClientHello,
NULL, // CLIENT_ID
NULL, // CLIENT_INFO
ipcCommandModule::OnClientAddName, ipcCommandModule::OnClientAddName,
ipcCommandModule::OnClientDelName, ipcCommandModule::OnClientDelName,
ipcCommandModule::OnClientAddTarget, ipcCommandModule::OnClientAddTarget,
ipcCommandModule::OnClientDelTarget, ipcCommandModule::OnClientDelTarget,
ipcCommandModule::OnQueryClientByName, ipcCommandModule::OnQueryClientByName
ipcCommandModule::OnQueryClientInfo,
ipcCommandModule::OnForward,
}; };
int type = IPCM_GetMsgType(rawMsg); int type = IPCM_GetType(rawMsg);
LOG(("IPCM_HandleMsg [type=%d]\n", type)); LOG(("IPCM_HandleMsg [type=%x]\n", type));
if (type < IPCM_MSG_TYPE_UNKNOWN) { if (!(type & IPCM_MSG_CLASS_REQ)) {
if (handlers[type]) { LOG(("not a request -- ignoring message\n"));
ipcCommandModule::MsgHandler handler = handlers[type]; return;
handler(client, rawMsg);
}
} }
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);
} }

View File

@ -211,7 +211,7 @@ IPC_ShutdownModuleReg()
} }
void void
IPC_NotifyClientUp(ipcClient *client) IPC_NotifyModulesClientUp(ipcClient *client)
{ {
for (int i = 0; i < ipcModuleCount; ++i) { for (int i = 0; i < ipcModuleCount; ++i) {
ipcModuleRegEntry &entry = ipcModules[i]; ipcModuleRegEntry &entry = ipcModules[i];
@ -221,7 +221,7 @@ IPC_NotifyClientUp(ipcClient *client)
} }
void void
IPC_NotifyClientDown(ipcClient *client) IPC_NotifyModulesClientDown(ipcClient *client)
{ {
for (int i = 0; i < ipcModuleCount; ++i) { for (int i = 0; i < ipcModuleCount; ++i) {
ipcModuleRegEntry &entry = ipcModules[i]; ipcModuleRegEntry &entry = ipcModules[i];

View File

@ -64,7 +64,7 @@ ipcModuleMethods *IPC_GetModuleByTarget(const nsID &target);
// //
// notifies all modules of client connect/disconnect // notifies all modules of client connect/disconnect
// //
void IPC_NotifyClientUp(ipcClient *); void IPC_NotifyModulesClientUp(ipcClient *);
void IPC_NotifyClientDown(ipcClient *); void IPC_NotifyModulesClientDown(ipcClient *);
#endif // !ipcModuleReg_h__ #endif // !ipcModuleReg_h__

View File

@ -73,6 +73,8 @@ IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg)
// next message sent to the client. // next message sent to the client.
if (msg->TestFlag(IPC_MSG_FLAG_SYNC_QUERY)) { if (msg->TestFlag(IPC_MSG_FLAG_SYNC_QUERY)) {
PR_ASSERT(client->GetExpectsSyncReply() == PR_FALSE); 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); client->SetExpectsSyncReply(PR_TRUE);
} }
@ -112,6 +114,32 @@ IPC_SendMsg(ipcClient *client, ipcMessage *msg)
return PR_FAILURE; return PR_FAILURE;
} }
void
IPC_NotifyClientUp(ipcClient *client)
{
// notify modules before other clients
IPC_NotifyModulesClientUp(client);
for (int i=0; i<ipcClientCount; ++i) {
if (&ipcClients[i] != client)
IPC_SendMsg(&ipcClients[i],
new ipcmMessageClientState(client->ID(), IPCM_CLIENT_STATE_UP));
}
}
void
IPC_NotifyClientDown(ipcClient *client)
{
// notify modules before other clients
IPC_NotifyModulesClientDown(client);
for (int i=0; i<ipcClientCount; ++i) {
if (&ipcClients[i] != client)
IPC_SendMsg(&ipcClients[i],
new ipcmMessageClientState(client->ID(), IPCM_CLIENT_STATE_DOWN));
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// IPC daemon methods // IPC daemon methods
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -73,4 +73,10 @@ PRStatus IPC_DispatchMsg(ipcClientHandle client, const ipcMessage *msg);
// //
PRStatus IPC_SendMsg(ipcClientHandle client, 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__ #endif // !IPCD_H__

View File

@ -45,6 +45,10 @@ include $(DEPTH)/config/autoconf.mk
MODULE = ipcd MODULE = ipcd
EXPORTS = \
ipcLockCID.h \
$(NULL)
XPIDLSRCS = \ XPIDLSRCS = \
ipcILockService.idl \ ipcILockService.idl \
ipcILockNotify.idl \ ipcILockNotify.idl \

View File

@ -74,18 +74,3 @@ interface ipcILockService : nsISupports
*/ */
void releaseLock(in string aLockName); 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} \
}
%}

View File

@ -79,7 +79,8 @@ struct ipcLockMsg
PRUint8 *IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen); 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); void IPC_UnflattenLockMsg(const PRUint8 *buf, PRUint32 bufLen, ipcLockMsg *msg);

View File

@ -42,29 +42,23 @@
#include "ipcLockProtocol.h" #include "ipcLockProtocol.h"
#include "ipcLog.h" #include "ipcLog.h"
static NS_DEFINE_IID(kIPCServiceCID, IPC_SERVICE_CID);
static const nsID kLockTargetID = IPC_LOCK_TARGETID; static const nsID kLockTargetID = IPC_LOCK_TARGETID;
ipcLockService::ipcLockService() //-----------------------------------------------------------------------------
{
}
ipcLockService::~ipcLockService()
{
}
nsresult nsresult
ipcLockService::Init() ipcLockService::Init()
{ {
nsresult rv; nsresult rv;
mIPCService = do_GetService(kIPCServiceCID, &rv); rv = IPC_Init();
if (NS_FAILED(rv)) return rv; 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 NS_IMETHODIMP
ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool waitIfBusy) ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool waitIfBusy)
@ -82,7 +76,7 @@ ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool
if (!buf) if (!buf)
return NS_ERROR_OUT_OF_MEMORY; 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); free(buf);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
LOG((" SendMessage failed [rv=%x]\n", rv)); LOG((" SendMessage failed [rv=%x]\n", rv));
@ -92,9 +86,16 @@ ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool
if (notify) { if (notify) {
nsCStringKey hashKey(lockName); nsCStringKey hashKey(lockName);
mPendingTable.Put(&hashKey, notify); 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 NS_IMETHODIMP
@ -112,7 +113,7 @@ ipcLockService::ReleaseLock(const char *lockName)
if (!buf) if (!buf)
return NS_ERROR_OUT_OF_MEMORY; 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); free(buf);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
@ -123,12 +124,13 @@ ipcLockService::ReleaseLock(const char *lockName)
} }
NS_IMETHODIMP 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; ipcLockMsg msg;
IPC_UnflattenLockMsg(data, dataLen, &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; nsresult status;
if (msg.opcode == IPC_LOCK_OP_STATUS_ACQUIRED) if (msg.opcode == IPC_LOCK_OP_STATUS_ACQUIRED)
@ -136,6 +138,16 @@ ipcLockService::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUi
else else
status = NS_ERROR_FAILURE; 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); NotifyComplete(msg.key, status);
return NS_OK; return NS_OK;
} }

View File

@ -39,9 +39,8 @@
#define ipcLockService_h__ #define ipcLockService_h__
#include "ipcILockService.h" #include "ipcILockService.h"
#include "ipcIService.h"
#include "ipcIMessageObserver.h"
#include "ipcList.h" #include "ipcList.h"
#include "ipcdclient.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsHashtable.h" #include "nsHashtable.h"
@ -53,18 +52,20 @@ public:
NS_DECL_IPCILOCKSERVICE NS_DECL_IPCILOCKSERVICE
NS_DECL_IPCIMESSAGEOBSERVER NS_DECL_IPCIMESSAGEOBSERVER
ipcLockService(); ipcLockService() : mSyncLockName(nsnull) {}
virtual ~ipcLockService(); ~ipcLockService() { IPC_Shutdown(); }
NS_HIDDEN_(nsresult) Init();
nsresult Init();
private: private:
void NotifyComplete(const char *lockName, nsresult status); NS_HIDDEN_(void) NotifyComplete(const char *lockName, nsresult status);
nsCOMPtr<ipcIService> mIPCService;
// map from lockname to locknotify for pending notifications // 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__ #endif // !ipcLockService_h__

View File

@ -119,66 +119,76 @@ ipcLockModule_AcquireLock(PRUint32 cid, PRUint8 flags, const char *key)
} }
} }
static void static PRBool
ipcLockModule_ReleaseLock(PRUint32 cid, const char *key) ipcLockModule_ReleaseLockHelper(PRUint32 cid, const char *key, ipcLockContext *ctx)
{ {
printf("$$$ releasing lock [key=%s]\n", key); 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) if (!gLockTable)
return; return;
ipcLockContext *ctx; ipcLockContext *ctx;
ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key); ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key);
if (ctx) { if (ctx && ipcLockModule_ReleaseLockHelper(cid, key, ctx))
// PL_HashTableRemove(gLockTable, key);
// 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;
}
}
}
}
} }
PR_STATIC_CALLBACK(PRIntn) PR_STATIC_CALLBACK(PRIntn)
ipcLockModule_ReleaseByCID(PLHashEntry *he, PRIntn i, void *arg) ipcLockModule_ReleaseByCID(PLHashEntry *he, PRIntn i, void *arg)
{ {
PRUint32 cid = *(PRUint32 *) 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; return HT_ENUMERATE_NEXT;
} }

View File

@ -97,6 +97,8 @@ tmTransactionService::~tmTransactionService() {
if (qmap) if (qmap)
delete qmap; delete qmap;
} }
IPC_Shutdown();
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -112,12 +114,15 @@ NS_IMPL_ISUPPORTS2(tmTransactionService,
NS_IMETHODIMP NS_IMETHODIMP
tmTransactionService::Init(const nsACString & aNamespace) { tmTransactionService::Init(const nsACString & aNamespace) {
// register with the IPC service nsresult rv;
ipcService = do_GetService("@mozilla.org/ipc/service;1");
if (!ipcService) rv = IPC_Init();
return NS_ERROR_FAILURE; if (NS_FAILED(rv))
if(NS_FAILED(ipcService->SetMessageObserver(kTransModuleID, this))) return rv;
return NS_ERROR_FAILURE;
rv = IPC_DefineTarget(kTransModuleID, this);
if (NS_FAILED(rv))
return rv;
// get the lock service // get the lock service
lockService = do_GetService("@mozilla.org/ipc/lock-service;1"); lockService = do_GetService("@mozilla.org/ipc/lock-service;1");
@ -185,6 +190,7 @@ tmTransactionService::Attach(const nsACString & aDomainName,
// acquire a lock if neccessary // acquire a lock if neccessary
if (aLockingCall) if (aLockingCall)
lockService->AcquireLock(joinedQueueName, nsnull, PR_TRUE); lockService->AcquireLock(joinedQueueName, nsnull, PR_TRUE);
// XXX need to handle lock failures
if (NS_SUCCEEDED(trans.Init(0, // no IPC client if (NS_SUCCEEDED(trans.Init(0, // no IPC client
TM_NO_ID, // qID gets returned to us TM_NO_ID, // qID gets returned to us
@ -269,7 +275,8 @@ tmTransactionService::PostTransaction(const nsACString & aDomainName,
// ipcIMessageObserver // ipcIMessageObserver
NS_IMETHODIMP NS_IMETHODIMP
tmTransactionService::OnMessageAvailable(const nsID & aTarget, tmTransactionService::OnMessageAvailable(const PRUint32 aSenderID,
const nsID & aTarget,
const PRUint8 *aData, const PRUint8 *aData,
PRUint32 aDataLength) { PRUint32 aDataLength) {
@ -319,13 +326,12 @@ void
tmTransactionService::SendMessage(tmTransaction *aTrans, PRBool aSync) { tmTransactionService::SendMessage(tmTransaction *aTrans, PRBool aSync) {
NS_ASSERTION(aTrans, "tmTransactionService::SendMessage called with null transaction"); NS_ASSERTION(aTrans, "tmTransactionService::SendMessage called with null transaction");
NS_ASSERTION(ipcService, "Failed to get the ipcService");
ipcService->SendMessage(0, IPC_SendMessage(0, kTransModuleID,
kTransModuleID, aTrans->GetRawMessage(),
aTrans->GetRawMessage(), aTrans->GetRawMessageLength());
aTrans->GetRawMessageLength(), if (aSync)
aSync); IPC_WaitMessage(0, kTransModuleID, nsnull, PR_INTERVAL_NO_TIMEOUT);
} }
void void

View File

@ -38,7 +38,7 @@
#ifndef _tmTransactionService_H_ #ifndef _tmTransactionService_H_
#define _tmTransactionService_H_ #define _tmTransactionService_H_
#include "ipcIService.h" #include "ipcdclient.h"
#include "ipcILockService.h" #include "ipcILockService.h"
#include "ipcIMessageObserver.h" #include "ipcIMessageObserver.h"
#include "ipcITransactionService.h" #include "ipcITransactionService.h"
@ -187,7 +187,6 @@ protected:
tmVector mQueueMaps; // queue - name - domain mappings tmVector mQueueMaps; // queue - name - domain mappings
tmVector mWaitingMessages; // messages sent before ATTACH_REPLY tmVector mWaitingMessages; // messages sent before ATTACH_REPLY
nsCOMPtr<ipcIService> ipcService; // cache the ipc service
nsCOMPtr<ipcILockService> lockService; // cache the lock service nsCOMPtr<ipcILockService> lockService; // cache the lock service
private: private:

View File

@ -64,7 +64,7 @@ inline void IPC_GetClientWindowName(PRUint32 pid, char *buf)
} }
#else #else
#include "prtypes.h" #include "nscore.h"
// //
// use UNIX domain socket // use UNIX domain socket
// //
@ -79,7 +79,7 @@ inline void IPC_GetClientWindowName(PRUint32 pid, char *buf)
#define IPC_MODULES_DIR "ipc/modules" #define IPC_MODULES_DIR "ipc/modules"
#endif #endif
void IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen); NS_HIDDEN_(void) IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen);
#endif #endif

View File

@ -95,8 +95,8 @@ public:
} }
private: private:
static ipcIDNode *FindNode (ipcIDNode *head, const nsID &id); static NS_HIDDEN_(ipcIDNode *) FindNode (ipcIDNode *head, const nsID &id);
static ipcIDNode *FindNodeBefore(ipcIDNode *head, const nsID &id); static NS_HIDDEN_(ipcIDNode *) FindNodeBefore(ipcIDNode *head, const nsID &id);
}; };
#endif // !ipcIDList_h__ #endif // !ipcIDList_h__

View File

@ -161,6 +161,17 @@ public:
PRBool IsEmpty() const { return mHead == NULL; } PRBool IsEmpty() const { return mHead == NULL; }
//
// moves contents of list to another list
//
void MoveTo(ipcList<T> &other)
{
other.mHead = mHead;
other.mTail = mTail;
mHead = NULL;
mTail = NULL;
}
protected: protected:
void AdvanceHead() void AdvanceHead()
{ {

View File

@ -38,6 +38,7 @@
#ifndef ipcLog_h__ #ifndef ipcLog_h__
#define ipcLog_h__ #define ipcLog_h__
#include "nscore.h"
#include "prtypes.h" #include "prtypes.h"
#ifdef DEBUG #ifdef DEBUG
@ -47,8 +48,8 @@
#ifdef IPC_LOGGING #ifdef IPC_LOGGING
extern PRBool ipcLogEnabled; extern PRBool ipcLogEnabled;
extern void IPC_InitLog(const char *prefix); extern NS_HIDDEN_(void) IPC_InitLog(const char *prefix);
extern void IPC_Log(const char *fmt, ...); extern NS_HIDDEN_(void) IPC_Log(const char *fmt, ...);
#define IPC_LOG(_args) \ #define IPC_LOG(_args) \
PR_BEGIN_MACRO \ PR_BEGIN_MACRO \

View File

@ -88,26 +88,28 @@ class ipcMessage
public: public:
ipcMessage() ipcMessage()
: mNext(NULL) : mNext(NULL)
, mMetaData(0)
, mMsgHdr(NULL) , mMsgHdr(NULL)
, mMsgOffset(0) , mMsgOffset(0)
, mMsgComplete(PR_FALSE) , mMsgComplete(PR_FALSE)
{ } { }
ipcMessage(const nsID &target, const char *data, PRUint32 dataLen) ipcMessage(const nsID &target, const char *data, PRUint32 dataLen)
: mNext(NULL) : mNext(NULL)
, mMetaData(0)
, mMsgHdr(NULL) , mMsgHdr(NULL)
, mMsgOffset(0) , mMsgOffset(0)
{ Init(target, data, dataLen); } { Init(target, data, dataLen); }
~ipcMessage(); ~ipcMessage() NS_HIDDEN;
// //
// reset message to uninitialized state // reset message to uninitialized state
// //
void Reset(); NS_HIDDEN_(void) Reset();
// //
// create a copy of this message // create a copy of this message
// //
ipcMessage *Clone() const; NS_HIDDEN_(ipcMessage *) Clone() const;
// //
// initialize message // initialize message
@ -117,7 +119,7 @@ public:
// data - message data (may be null to leave data uninitialized) // data - message data (may be null to leave data uninitialized)
// dataLen - message data len // 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 // copy data into the message's data section, starting from offset. this
@ -128,7 +130,7 @@ public:
// data - data to write // data - data to write
// dataLen - number of bytes 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 // access message flags
@ -161,32 +163,39 @@ public:
// data - message data (must not be null) // data - message data (must not be null)
// dataLen - message data length // dataLen - message data length
// //
PRBool Equals(const nsID &target, const char *data, PRUint32 dataLen) const; NS_HIDDEN_(PRBool) Equals(const nsID &target, const char *data, PRUint32 dataLen) const;
PRBool Equals(const ipcMessage *msg) const; NS_HIDDEN_(PRBool) Equals(const ipcMessage *msg) const;
// //
// write the message to a buffer segment; segment need not be large // write the message to a buffer segment; segment need not be large
// enough to hold entire message. called repeatedly. // enough to hold entire message. called repeatedly.
// //
PRStatus WriteTo(char *buf, NS_HIDDEN_(PRStatus) WriteTo(char *buf,
PRUint32 bufLen, PRUint32 bufLen,
PRUint32 *bytesWritten, PRUint32 *bytesWritten,
PRBool *complete); PRBool *complete);
// //
// read the message from a buffer segment; segment need not contain // read the message from a buffer segment; segment need not contain
// the entire messgae. called repeatedly. // the entire messgae. called repeatedly.
// //
PRStatus ReadFrom(const char *buf, NS_HIDDEN_(PRStatus) ReadFrom(const char *buf,
PRUint32 bufLen, PRUint32 bufLen,
PRUint32 *bytesRead, PRUint32 *bytesRead,
PRBool *complete); PRBool *complete);
// //
// a message can be added to a singly-linked list. // a message can be added to a singly-linked list.
// //
class ipcMessage *mNext; 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: private:
ipcMessageHeader *mMsgHdr; ipcMessageHeader *mMsgHdr;

View File

@ -43,16 +43,39 @@ ipcMessage_DWORD_STR::ipcMessage_DWORD_STR(const nsID &target,
const char *second) const char *second)
{ {
int sLen = strlen(second); int sLen = strlen(second);
Init(target, NULL, sizeof(first) + sLen + 1); Init(target, NULL, 4 + sLen + 1);
SetData(0, (char *) &first, sizeof(first)); SetData(0, (char *) &first, 4);
SetData(sizeof(first), second, sLen + 1); 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, ipcMessage_DWORD_ID::ipcMessage_DWORD_ID(const nsID &target,
PRUint32 first, PRUint32 first,
const nsID &second) const nsID &second)
{ {
Init(target, NULL, sizeof(first) + sizeof(nsID)); Init(target, NULL, 4 + sizeof(nsID));
SetData(0, (char *) &first, sizeof(first)); SetData(0, (char *) &first, 4);
SetData(sizeof(first), (char *) &second, sizeof(nsID)); 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));
} }

View File

@ -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 class ipcMessage_DWORD_STR : public ipcMessage
{ {
public: 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 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 class ipcMessage_DWORD_ID : public ipcMessage
{ {
public: 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 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__ #endif // !ipcMessagePrimitives_h__

View File

@ -40,7 +40,7 @@
#include <string.h> #include <string.h>
#include "plstr.h" #include "plstr.h"
#include "xpcom-config.h" #include "nscore.h"
#include "ipcList.h" #include "ipcList.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -101,8 +101,8 @@ public:
} }
private: private:
static ipcStringNode *FindNode (ipcStringNode *head, const char *str); static NS_HIDDEN_(ipcStringNode *) FindNode (ipcStringNode *head, const char *str);
static ipcStringNode *FindNodeBefore(ipcStringNode *head, const char *str); static NS_HIDDEN_(ipcStringNode *) FindNodeBefore(ipcStringNode *head, const char *str);
}; };
#endif // !ipcStringList_h__ #endif // !ipcStringList_h__

View File

@ -37,7 +37,7 @@
#include <string.h> #include <string.h>
#include "ipcm.h" #include "ipcm.h"
#include "prlog.h" #include "pratom.h"
const nsID IPCM_TARGET = const nsID IPCM_TARGET =
{ /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */ { /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */
@ -47,6 +47,15 @@ const nsID IPCM_TARGET =
{0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50} {0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50}
}; };
PRUint32
IPCM_NewRequestIndex()
{
static PRInt32 sRequestIndex;
return (PRUint32) PR_AtomicIncrement(&sRequestIndex);
}
#if 0
// //
// MSG_TYPE values // 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 ipcmMessageQueryClientByName::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME;
const PRUint32 ipcmMessageQueryClientInfo::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_INFO; const PRUint32 ipcmMessageQueryClientInfo::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_INFO;
const PRUint32 ipcmMessageForward::MSG_TYPE = IPCM_MSG_TYPE_FORWARD; const PRUint32 ipcmMessageForward::MSG_TYPE = IPCM_MSG_TYPE_FORWARD;
const PRUint32 ipcmMessageClientStatus::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_STATUS;
// //
// CLIENT_INFO message // CLIENT_INFO message
@ -71,6 +81,8 @@ const PRUint32 ipcmMessageForward::MSG_TYPE = IPCM_MSG_TYPE_FORWARD;
// +--------------------+--------------------+ // +--------------------+--------------------+
// | DWORD : clientID | // | DWORD : clientID |
// +--------------------+--------------------+ // +--------------------+--------------------+
// | DWORD : requestIndex |
// +--------------------+--------------------+
// | WORD : nameStart | WORD : nameCount | // | WORD : nameStart | WORD : nameCount |
// +--------------------+--------------------+ // +--------------------+--------------------+
// | WORD : targetStart | WORD : targetCount | // | WORD : targetStart | WORD : targetCount |
@ -95,18 +107,20 @@ struct ipcmClientInfoHeader
{ {
PRUint32 mType; PRUint32 mType;
PRUint32 mID; PRUint32 mID;
PRUint32 mRequestIndex;
PRUint16 mNameStart; PRUint16 mNameStart;
PRUint16 mNameCount; PRUint16 mNameCount;
PRUint16 mTargetStart; PRUint16 mTargetStart;
PRUint16 mTargetCount; 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}; ipcmClientInfoHeader hdr = {0};
hdr.mType = MSG_TYPE; hdr.mType = MSG_TYPE;
hdr.mID = cID; hdr.mID = cID;
hdr.mRequestIndex = rIdx;
hdr.mNameStart = sizeof(hdr); hdr.mNameStart = sizeof(hdr);
PRUint32 i, namesLen = 0; PRUint32 i, namesLen = 0;
@ -163,6 +177,13 @@ ipcmMessageClientInfo::ClientID() const
return hdr->mID; return hdr->mID;
} }
PRUint32
ipcmMessageClientInfo::RequestIndex() const
{
ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data();
return hdr->mRequestIndex;
}
PRUint32 PRUint32
ipcmMessageClientInfo::NameCount() const ipcmMessageClientInfo::NameCount() const
{ {
@ -203,6 +224,7 @@ ipcmMessageClientInfo::NextTarget(const nsID *target) const
target = NULL; target = NULL;
return target; return target;
} }
#endif
// //
// FORWARD message // 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 nsID &target,
const char *data, const char *data,
PRUint32 dataLen) PRUint32 dataLen)
{ {
int len = sizeof(MSG_TYPE) + // MSG_TYPE int len = sizeof(ipcmMessageHeader) + // IPCM header
sizeof(cID) + // cID sizeof(cID) + // cID
IPC_MSG_HEADER_SIZE + // innerMsgHeader IPC_MSG_HEADER_SIZE + // innerMsgHeader
dataLen; // innerMsgData dataLen; // innerMsgData
Init(IPCM_TARGET, NULL, len); Init(IPCM_TARGET, NULL, len);
SetData(0, (char *) &MSG_TYPE, sizeof(MSG_TYPE)); ipcmMessageHeader ipcmHdr =
SetData(4, (char *) &cID, sizeof(cID)); { type, IPCM_NewRequestIndex() };
SetData(0, (char *) &ipcmHdr, sizeof(ipcmHdr));
SetData(sizeof(ipcmHdr), (char *) &cID, sizeof(cID));
ipcMessageHeader hdr; ipcMessageHeader hdr;
hdr.mLen = IPC_MSG_HEADER_SIZE + dataLen; hdr.mLen = IPC_MSG_HEADER_SIZE + dataLen;
@ -239,7 +265,7 @@ ipcmMessageForward::ipcmMessageForward(PRUint32 cID,
hdr.mFlags = 0; hdr.mFlags = 0;
hdr.mTarget = target; hdr.mTarget = target;
SetData(8, (char *) &hdr, IPC_MSG_HEADER_SIZE); SetData(sizeof(ipcmHdr) + sizeof(cID), (char *) &hdr, IPC_MSG_HEADER_SIZE);
if (data) if (data)
SetInnerData(0, data, dataLen); SetInnerData(0, data, dataLen);
} }
@ -247,31 +273,31 @@ ipcmMessageForward::ipcmMessageForward(PRUint32 cID,
void void
ipcmMessageForward::SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen) 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 PRUint32
ipcmMessageForward::DestClientID() const ipcmMessageForward::ClientID() const
{ {
return ((PRUint32 *) Data())[1]; return ((PRUint32 *) Data())[2];
} }
const nsID & const nsID &
ipcmMessageForward::InnerTarget() const ipcmMessageForward::InnerTarget() const
{ {
ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 8); ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 12);
return hdr->mTarget; return hdr->mTarget;
} }
const char * const char *
ipcmMessageForward::InnerData() const ipcmMessageForward::InnerData() const
{ {
return Data() + 8 + IPC_MSG_HEADER_SIZE; return Data() + 12 + IPC_MSG_HEADER_SIZE;
} }
PRUint32 PRUint32
ipcmMessageForward::InnerDataLen() const ipcmMessageForward::InnerDataLen() const
{ {
ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 8); ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 12);
return hdr->mLen - IPC_MSG_HEADER_SIZE; return hdr->mLen - IPC_MSG_HEADER_SIZE;
} }

View File

@ -41,47 +41,291 @@
#include "ipcMessage.h" #include "ipcMessage.h"
#include "ipcMessagePrimitives.h" #include "ipcMessagePrimitives.h"
//-----------------------------------------------------------------------------
// //
// IPCM (IPC Manager) protocol support // IPCM (IPC Manager) protocol support
// //
// The IPCM message target identifier:
extern const nsID IPCM_TARGET; extern const nsID IPCM_TARGET;
enum { //
IPCM_MSG_TYPE_PING, // Every IPCM message has the following structure:
IPCM_MSG_TYPE_ERROR, //
IPCM_MSG_TYPE_CLIENT_HELLO, // +-----------------------------------------+
IPCM_MSG_TYPE_CLIENT_ID, // | (ipc message header) |
IPCM_MSG_TYPE_CLIENT_INFO, // +-----------------------------------------+
IPCM_MSG_TYPE_CLIENT_ADD_NAME, // | DWORD : type |
IPCM_MSG_TYPE_CLIENT_DEL_NAME, // +-----------------------------------------+
IPCM_MSG_TYPE_CLIENT_ADD_TARGET, // | DWORD : requestIndex |
IPCM_MSG_TYPE_CLIENT_DEL_TARGET, // +-----------------------------------------+
IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME, // . .
IPCM_MSG_TYPE_QUERY_CLIENT_INFO, // . (payload) .
// IPCM_MSG_TYPE_QUERY_MODULE, // check if module exists // . .
IPCM_MSG_TYPE_FORWARD, // +-----------------------------------------+
IPCM_MSG_TYPE_UNKNOWN // unknown message type //
// 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. // returns IPCM message type.
// //
static inline int 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 // return IPCM message request index.
// and parsing of IPCM messages. each class subclasses ipcMessage, but //
// adds no additional member variables. operator new should be used static inline PRUint32
IPCM_GetRequestIndex(const ipcMessage *msg)
{
return ((const ipcmMessageHeader *) msg->Data())->mRequestIndex;
}
//
// return a request index that is unique to this process.
//
NS_HIDDEN_(PRUint32)
IPCM_NewRequestIndex();
//-----------------------------------------------------------------------------
//
// The IPCM protocol is detailed below:
//
// REQUESTS
//
// req: IPCM_MSG_REQ_PING
// ack: IPCM_MSG_ACK_RESULT
//
// A PING can be sent from either a client to the daemon, or from the daemon
// to a client. The expected acknowledgement is a RESULT message with a status
// code of 0.
//
// This request message has no payload.
//
//
// req: IPCM_MSG_REQ_FORWARD
// ack: IPCM_MSG_ACK_RESULT
//
// A FORWARD is sent when a client wishes to send a message to another client.
// The payload of this message is another message that should be forwarded by
// the daemon's IPCM to the specified client. The expected acknowledgment is
// a RESULT message with a status code indicating success or failure.
//
// When the daemon receives a FORWARD message, it creates a PSH_FORWARD message
// and sends that on to the destination client.
//
// This request message has as its payload:
//
// +-----------------------------------------+
// | DWORD : clientID |
// +-----------------------------------------+
// | (innerMsgHeader) |
// +-----------------------------------------+
// | (innerMsgData) |
// +-----------------------------------------+
//
//
// req: IPCM_MSG_REQ_CLIENT_HELLO
// ack: IPCM_MSG_REQ_CLIENT_ID <or> IPCM_MSG_REQ_RESULT
//
// A CLIENT_HELLO is sent when a client connects to the IPC daemon. The
// expected acknowledgement is a CLIENT_ID message informing the new client of
// its ClientID. If for some reason the IPC daemon cannot accept the new
// client, it returns a RESULT message with a failure status code.
//
// This request message has no payload.
//
//
// req: IPCM_MSG_REQ_CLIENT_ADD_NAME
// ack: IPCM_MSG_ACK_RESULT
//
// A CLIENT_ADD_NAME is sent when a client wishes to register an additional
// name for itself. The expected acknowledgement is a RESULT message with a
// status code indicating success or failure.
//
// This request message has as its payload a null-terminated ASCII character
// string indicating the name of the client.
//
//
// req: IPCM_MSG_REQ_CLIENT_DEL_NAME
// ack: IPCM_MSG_ACK_RESULT
//
// A CLIENT_DEL_NAME is sent when a client wishes to unregister a name that it
// has registered. The expected acknowledgement is a RESULT message with a
// status code indicating success or failure.
//
// This request message has as its payload a null-terminated ASCII character
// string indicating the name of the client.
//
//
// req: IPCM_MSG_REQ_CLIENT_ADD_TARGET
// ack: IPCM_MSG_ACK_RESULT
//
// A CLIENT_ADD_TARGET is sent when a client wishes to register an additional
// target that it supports. The expected acknowledgement is a RESULT message
// with a status code indicating success or failure.
//
// This request message has as its payload a 128-bit UUID indicating the
// target to add.
//
//
// req: IPCM_MSG_REQ_CLIENT_DEL_TARGET
// ack: IPCM_MSG_ACK_RESULT
//
// A CLIENT_DEL_TARGET is sent when a client wishes to unregister a target
// that it has registered. The expected acknowledgement is a RESULT message
// with a status code indicating success or failure.
//
// This request message has as its payload a 128-bit UUID indicating the
// target to remove.
//
//
// req: IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME
// ack: IPCM_MSG_ACK_CLIENT_ID <or> IPCM_MSG_ACK_RESULT
//
// A QUERY_CLIENT_BY_NAME may be sent by a client to discover the client that
// is known by a common name. If more than one client matches the name, then
// only the ID of the more recently registered client is returned. The
// expected acknowledgement is a CLIENT_ID message carrying the ID of the
// corresponding client. If no client matches the given name or if some error
// occurs, then a RESULT message with a failure status code is returned.
//
// This request message has as its payload a null-terminated ASCII character
// string indicating the client name to query.
//
// ACKNOWLEDGEMENTS
//
// ack: IPCM_MSG_ACK_RESULT
//
// This acknowledgement is returned to indicate a success or failure status.
//
// The payload consists of a single DWORD value.
//
// Possible status codes are listed below (negative values indicate failure
// codes):
//
#define IPCM_OK 0 // success: generic
#define IPCM_ERROR_GENERIC -1 // failure: generic
#define IPCM_ERROR_NO_CLIENT -2 // failure: client does not exist
//
// 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.: // to allocate one of the IPCM helper classes, e.g.:
// //
// ipcMessage *msg = new ipcmMessageClientHello("foo"); // 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: // to the following:
// //
// void func(const ipcMessage *unknown) // void func(const ipcMessage *unknown)
@ -94,229 +338,162 @@ IPCM_GetMsgType(const ipcMessage *msg)
// } // }
// } // }
// //
// in other words, these classes are very very lightweight.
//
// // REQUESTS
// IPCM_MSG_TYPE_PING
// class ipcmMessagePing : public ipcMessage_DWORD_DWORD
// 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
{ {
public: public:
static const PRUint32 MSG_TYPE;
ipcmMessagePing() 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 class ipcmMessageForward : public ipcMessage
{ {
public: public:
static const PRUint32 MSG_TYPE; // @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
// params: // @param data the message data
// clientID - the client to which the message should be forwarded // @param dataLen the message data length
// target - the message target ipcmMessageForward(PRUint32 type,
// data - the message data PRUint32 clientID,
// dataLen - the message data length
//
ipcmMessageForward(PRUint32 clientID,
const nsID &target, const nsID &target,
const char *data, const char *data,
PRUint32 dataLen); PRUint32 dataLen) NS_HIDDEN;
//
// set inner message data, constrained to the data length passed // set inner message data, constrained to the data length passed
// to this class's constructor. // to this class's constructor.
// NS_HIDDEN_(void) SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen);
void SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen);
PRUint32 DestClientID() const; NS_HIDDEN_(PRUint32) ClientID() const;
const nsID &InnerTarget() const; NS_HIDDEN_(const nsID &) InnerTarget() const;
const char *InnerData() const; NS_HIDDEN_(const char *) InnerData() const;
PRUint32 InnerDataLen() 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__ #endif // !ipcm_h__

View File

@ -40,6 +40,8 @@
#include "ipcIClientQueryHandler.h" #include "ipcIClientQueryHandler.h"
#include "ipcILockService.h" #include "ipcILockService.h"
#include "ipcILockNotify.h" #include "ipcILockNotify.h"
#include "ipcCID.h"
#include "ipcLockCID.h"
#include "nsIEventQueueService.h" #include "nsIEventQueueService.h"
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
@ -75,7 +77,6 @@ static const nsID kTestTargetID =
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static nsIEventQueue* gEventQ = nsnull; static nsIEventQueue* gEventQ = nsnull;
static PRBool gKeepRunning = PR_TRUE; static PRBool gKeepRunning = PR_TRUE;
//static PRInt32 gMsgCount = 0;
static ipcIService *gIpcServ = nsnull; static ipcIService *gIpcServ = nsnull;
static ipcILockService *gIpcLockServ = 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); printf("*** sending message: [to-client=%u dataLen=%u]\n", cID, dataLen);
ipc->SendMessage(cID, target, (const PRUint8 *) data, dataLen, sync); nsresult rv;
// gMsgCount++;
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: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_IPCIMESSAGEOBSERVER NS_DECL_IPCIMESSAGEOBSERVER
myIpcMessageObserver() {}
}; };
NS_IMPL_ISUPPORTS1(myIpcMessageObserver, ipcIMessageObserver) NS_IMPL_ISUPPORTS1(myIpcMessageObserver, ipcIMessageObserver)
NS_IMETHODIMP 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); printf("*** got message: [sender=%u data=%s]\n", sender, (const char *) data);
// if (--gMsgCount == 0)
// gKeepRunning = PR_FALSE;
return NS_OK; return NS_OK;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#if 0
class myIpcClientQueryHandler : public ipcIClientQueryHandler class myIpcClientQueryHandler : public ipcIClientQueryHandler
{ {
public: public:
@ -160,6 +166,7 @@ myIpcClientQueryHandler::OnQueryComplete(PRUint32 aQueryID,
return NS_OK; return NS_OK;
} }
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -205,16 +212,17 @@ int main(int argc, char **argv)
rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ);
RETURN_IF_FAILED(rv, "GetThreadEventQueue"); RETURN_IF_FAILED(rv, "GetThreadEventQueue");
printf("*** getting ipc service\n");
nsCOMPtr<ipcIService> ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv)); nsCOMPtr<ipcIService> ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv));
RETURN_IF_FAILED(rv, "do_GetService(ipcServ)"); RETURN_IF_FAILED(rv, "do_GetService(ipcServ)");
NS_ADDREF(gIpcServ = ipcServ); NS_ADDREF(gIpcServ = ipcServ);
if (argc > 1) { if (argc > 1) {
printf("*** using client name [%s]\n", argv[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[] = const char data[] =
"01 this is a really long message.\n" "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"; "60 this is a really long message.\n";
SendMsg(ipcServ, 0, kTestTargetID, data, sizeof(data), PR_TRUE); SendMsg(ipcServ, 0, kTestTargetID, data, sizeof(data), PR_TRUE);
PRUint32 queryID; // PRUint32 queryID;
nsCOMPtr<ipcIClientQueryHandler> handler(new myIpcClientQueryHandler()); // nsCOMPtr<ipcIClientQueryHandler> handler(new myIpcClientQueryHandler());
ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID); // 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 // test lock service