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
EXPORTS = \
ipcdclient.h \
ipcCID.h \
$(NULL)
XPIDLSRCS = \
ipcIService.idl \
ipcIMessageObserver.idl \
ipcIClientObserver.idl \
ipcIClientQueryHandler.idl \
ipcIClientInfo.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

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

View File

@ -44,6 +44,9 @@
interface ipcIMessageObserver : nsISupports
{
/**
* @param aSenderID
* the client id of the sender of this message. if sent by the
* daemon (or a deamon module), then this will have a value of 0.
* @param aTarget
* the target of the message, corresponding to the target this
* observer was registered under. this parameter is passed to allow
@ -53,7 +56,8 @@ interface ipcIMessageObserver : nsISupports
* @param aDataLen
* the data length of the message.
*/
void onMessageAvailable(in nsIDRef aTarget,
void onMessageAvailable(in unsigned long aSenderID,
in nsIDRef aTarget,
[array, const, size_is(aDataLen)]
in octet aData,
in unsigned long aDataLen);

View File

@ -39,7 +39,6 @@
interface ipcIMessageObserver;
interface ipcIClientObserver;
interface ipcIClientQueryHandler;
/**
* ipcIService
@ -82,7 +81,7 @@ interface ipcIService : nsISupports
*
* @throws NS_ERROR_NOT_AVAILABLE if no connection to the IPC daemon.
*/
readonly attribute unsigned long clientID;
readonly attribute unsigned long ID;
/**
* this process can appear under several client names. use the following
@ -95,71 +94,42 @@ interface ipcIService : nsISupports
*
* XXX An IPC client name resembles a XPCOM contract ID.
*/
void addClientName(in string aName);
void removeClientName(in string aName);
void addName(in string aName);
void removeName(in string aName);
/**
* add a new observer of client status change notifications.
*/
void addClientObserver(in ipcIClientObserver aObserver);
/**
* remove an observer of client status change notifications.
*/
void removeClientObserver(in ipcIClientObserver aObserver);
/**************************************************************************
* client query methods
*/
/**
* query info about a particular client given its client name. the
* observer's onClientInfo method is called with the result of the lookup,
* or if there is no client matching the given name, the observer's
* onClientDown method will be called instead.
*
* @param aName
* the name of the client being queried.
* @param aHandler
* the handler to be notified with result.
* @param aSync
* block the calling thread until the query completes.
*
* @return integer value identifying this query.
* resolve the given client name to the id of a connected client. this
* involves a round trip to the daemon, and as a result the calling thread
* may block on this function call while waiting for the daemon to respond.
*/
unsigned long queryClientByName(in string aName,
in ipcIClientQueryHandler aHandler,
in boolean aSync);
unsigned long resolveClientName(in string aName);
/**
* query info about a particular client given its client ID. the observer's
* onClientInfo method is called with the result of the lookup, or if there
* is no client matching the given name, the observer's onClientDown method
* will be called instead.
*
* @param aClientID
* the ID of the client being queried.
* @param aHandler
* the handler to be notified with result.
* @param aSync
* block the calling thread until the query completes.
*
* @return integer value identifying this query.
* tests whether a particular client is connected to the IPC daemon.
*/
unsigned long queryClientByID(in unsigned long aClientID,
in ipcIClientQueryHandler aHandler,
in boolean aSync);
boolean clientExists(in unsigned long aClientID);
/**
* called to cancel a pending query.
*
* @param aQueryID
* the return value from one of the "query" methods.
*/
void cancelQuery(in unsigned long aQueryID);
/**
* set client observer. observer's onClientUp method is called whenever
* a new client comes online, and the observer's onClientDown method is
* called whenever a client goes offline.
*
* @param aObserver
* the client observer.
*/
void setClientObserver(in ipcIClientObserver aObserver);
// XXX need other functions to enumerate clients, clients implementing targets, etc.
// enumerator getClients();
// enumerator getClientsSupportingTarget(in nsIDRef aTarget);
// enumerator getClientNames(in unsigned long aClientID);
// enumerator getClientTargets(in unsigned long aClientID);
/**************************************************************************
@ -176,7 +146,7 @@ interface ipcIService : nsISupports
* the message observer to receive incoming messages for the
* specified target. pass null to remove the existing observer.
*/
void setMessageObserver(in nsIDRef aTarget, in ipcIMessageObserver aObserver);
void defineTarget(in nsIDRef aTarget, in ipcIMessageObserver aObserver);
/**
* send message asynchronously to a client or a module in the IPC daemon.
@ -192,33 +162,50 @@ interface ipcIService : nsISupports
* the message data.
* @param aDataLen
* the message length.
* @param aSync
* block the calling thread until a response to this message is
* received.
*/
void sendMessage(in unsigned long aClientID,
void sendMessage(in unsigned long aReceiverID,
in nsIDRef aTarget,
[array, const, size_is(aDataLen)]
in octet aData,
in unsigned long aDataLen,
in boolean aSync);
in unsigned long aDataLen);
/**
* block the calling thread until a matching message is received.
*
* @param aSenderID
* pass 0 to wait for a message from the daemon. pass PR_UINT32_MAX
* to wait for a message from any source. otherwise, pass a client
* id to wait for a message from that particular client.
* @param aTarget
* wait for a message to be delivered to this target.
* @param aObserver
* this observer's OnMessageAvailable method is called when a
* matching message is available. pass null to use the default
* observer associated with aTarget.
* @param aTimeout
* indicates maximum length of time in milliseconds that this
* function may block the calling thread.
*
* @throws IPC_ERROR_WOULD_BLOCK if the timeout expires.
*
* the observer's OnMessageAvailable method may throw IPC_WAIT_NEXT_MESSAGE
* to indicate that it does not wish to handle the message that it was
* given, and that it will wait to be called with the next message. this
* enables the observer to keep messages in the queue that do not match the
* desired message. messages that remain in the queue will be dispatched
* asynchronously to the default message handler after waitMessage finishes.
*
* NOTE: this function may hang the calling thread until a matching message
* is received, so use it with caution.
*/
void waitMessage(in unsigned long aSenderID,
in nsIDRef aTarget,
in ipcIMessageObserver aObserver,
in unsigned long aTimeout);
};
%{C++
// singleton implementing ipcIService
#define IPC_SERVICE_CLASSNAME \
"ipcService"
#define IPC_SERVICE_CONTRACTID \
"@mozilla.org/ipc/service;1"
#define IPC_SERVICE_CID \
{ /* 9f12676a-5168-4a08-beb8-edf8a593a1ca */ \
0x9f12676a, \
0x5168, \
0x4a08, \
{0xbe, 0xb8, 0xed, 0xf8, 0xa5, 0x93, 0xa1, 0xca} \
}
// category and observer event defines
// category and observer event defines (XXX not yet implemented)
#define IPC_SERVICE_STARTUP_CATEGORY "ipc-startup-category"
#define IPC_SERVICE_STARTUP_TOPIC "ipc-startup"
#define IPC_SERVICE_SHUTDOWN_TOPIC "ipc-shutdown"

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)
CPPSRCS = \
ipcdclient.cpp \
ipcService.cpp \
ipcTransport.cpp \
ipcModuleFactory.cpp \
$(NULL)

View File

@ -42,6 +42,9 @@
class ipcMessage;
#define IPC_METHOD_PRIVATE_(type) NS_HIDDEN_(type)
#define IPC_METHOD_PRIVATE IPC_METHOD_PRIVATE_(nsresult)
/* ------------------------------------------------------------------------- */
/* Platform specific IPC connection API.
*/
@ -57,7 +60,7 @@ class ipcMessage;
*
* NOTE: This function must be called on the main thread.
*/
nsresult IPC_Connect(const char *daemonPath);
IPC_METHOD_PRIVATE IPC_Connect(const char *daemonPath);
/**
* IPC_Disconnect
@ -68,7 +71,7 @@ nsresult IPC_Connect(const char *daemonPath);
*
* NOTE: This function must be called on the main thread.
*/
nsresult IPC_Disconnect();
IPC_METHOD_PRIVATE IPC_Disconnect();
/**
* IPC_SendMsg
@ -82,7 +85,7 @@ nsresult IPC_Disconnect();
*
* NOTE: This function may be called on any thread.
*/
nsresult IPC_SendMsg(ipcMessage *msg);
IPC_METHOD_PRIVATE IPC_SendMsg(ipcMessage *msg);
/* ------------------------------------------------------------------------- */
/* Cross-platform IPC connection methods.
@ -99,7 +102,7 @@ nsresult IPC_SendMsg(ipcMessage *msg);
* @param daemonPath
* Specifies the path to the IPC daemon executable.
*/
nsresult IPC_SpawnDaemon(const char *daemonPath);
IPC_METHOD_PRIVATE IPC_SpawnDaemon(const char *daemonPath);
/* ------------------------------------------------------------------------- */
/* IPC connection callbacks (not implemented by the connection code).
@ -115,7 +118,7 @@ nsresult IPC_SpawnDaemon(const char *daemonPath);
* described by the |error| parameter. If |error| is NS_OK, then it means the
* connection was closed in response to a call to IPC_Disconnect.
*/
void IPC_OnConnectionEnd(nsresult error);
IPC_METHOD_PRIVATE_(void) IPC_OnConnectionEnd(nsresult error);
/**
* IPC_OnMessageAvailable
@ -124,6 +127,6 @@ void IPC_OnConnectionEnd(nsresult error);
* daemon. The ipcMessage object, |msg|, must be deleted by the implementation
* of IPC_OnMessageAvailable when the object is no longer needed.
*/
void IPC_OnMessageAvailable(ipcMessage *msg);
IPC_METHOD_PRIVATE_(void) IPC_OnMessageAvailable(ipcMessage *msg);
#endif // ipcConnection_h__

View File

@ -40,6 +40,8 @@
#include "nsICategoryManager.h"
#include "ipcService.h"
#include "ipcConfig.h"
#include "ipcCID.h"
#include "ipcLockCID.h"
//-----------------------------------------------------------------------------
// Define the contructor function for the objects
@ -93,6 +95,45 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcLockService, Init)
#include "tmTransactionService.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService)
#if 0
#include "ipcDConnectService.h"
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcDConnectService, Init)
// enable this code to make the IPC DCONNECT service auto-start.
NS_METHOD
ipcDConnectServiceRegisterProc(nsIComponentManager *aCompMgr,
nsIFile *aPath,
const char *registryLocation,
const char *componentType,
const nsModuleComponentInfo *info)
{
//
// add ipcService to the XPCOM startup category
//
nsCOMPtr<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
// information like the function to create an instance, contractid, and
@ -118,6 +159,12 @@ static const nsModuleComponentInfo components[] = {
IPC_TRANSACTIONSERVICE_CID,
IPC_TRANSACTIONSERVICE_CONTRACTID,
tmTransactionServiceConstructor },
#if 0
{ IPC_DCONNECTSERVICE_CLASSNAME,
IPC_DCONNECTSERVICE_CID,
IPC_DCONNECTSERVICE_CONTRACTID,
ipcDConnectServiceConstructor },
#endif
};
//-----------------------------------------------------------------------------

View File

@ -14,9 +14,8 @@
*
* The Original Code is Mozilla IPC.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* The Initial Developer of the Original Code is IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
@ -36,472 +35,69 @@
*
* ***** END LICENSE BLOCK ***** */
#include <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 "ipcMessageUtils.h"
#include "ipcm.h"
#include "ipcIMessageObserver.h"
#include "ipcIClientObserver.h"
#include "ipcIClientQueryHandler.h"
//-----------------------------------------------------------------------------
// helpers
//-----------------------------------------------------------------------------
static PRBool PR_CALLBACK
ipcReleaseMessageObserver(nsHashKey *aKey, void *aData, void* aClosure)
{
ipcIMessageObserver *obs = (ipcIMessageObserver *) aData;
NS_RELEASE(obs);
return PR_TRUE;
}
//----------------------------------------------------------------------------
// ipcClientQuery
//----------------------------------------------------------------------------
class ipcClientQuery
{
public:
ipcClientQuery(PRUint32 cID, ipcIClientQueryHandler *handler)
: mNext(nsnull)
, mQueryID(++gLastQueryID)
, mClientID(cID)
, mHandler(handler)
{ }
static PRUint32 gLastQueryID;
void SetClientID(PRUint32 cID) { mClientID = cID; }
void OnQueryComplete(nsresult status, const ipcmMessageClientInfo *msg);
PRUint32 QueryID() { return mQueryID; }
PRBool IsCanceled() { return mHandler.get() == NULL; }
ipcClientQuery *mNext;
private:
PRUint32 mQueryID;
PRUint32 mClientID;
nsCOMPtr<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_IMPL_ISUPPORTS1(ipcService, ipcIService)
NS_IMETHODIMP
ipcService::GetClientID(PRUint32 *clientID)
ipcService::GetID(PRUint32 *aID)
{
NS_ENSURE_TRUE(mClientID != 0, NS_ERROR_NOT_INITIALIZED);
*clientID = mClientID;
return NS_OK;
return IPC_GetID(aID);
}
NS_IMETHODIMP
ipcService::AddClientName(const char *name)
ipcService::AddName(const char *aName)
{
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
ipcMessage *msg = new ipcmMessageClientAddName(name);
if (!msg)
return NS_ERROR_OUT_OF_MEMORY;
return mTransport->SendMsg(msg);
return IPC_AddName(aName);
}
NS_IMETHODIMP
ipcService::RemoveClientName(const char *name)
ipcService::RemoveName(const char *aName)
{
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
ipcMessage *msg = new ipcmMessageClientDelName(name);
if (!msg)
return NS_ERROR_OUT_OF_MEMORY;
return mTransport->SendMsg(msg);
return IPC_RemoveName(aName);
}
NS_IMETHODIMP
ipcService::QueryClientByName(const char *name,
ipcIClientQueryHandler *handler,
PRBool sync,
PRUint32 *queryID)
ipcService::AddClientObserver(ipcIClientObserver *aObserver)
{
if (!mTransport)
return NS_ERROR_NOT_AVAILABLE;
ipcMessage *msg;
msg = new ipcmMessageQueryClientByName(name);
if (!msg)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
rv = mTransport->SendMsg(msg, sync);
if (NS_FAILED(rv)) return rv;
ipcClientQuery *query = new ipcClientQuery(0, handler);
if (queryID)
*queryID = query->QueryID();
mQueryQ.Append(query);
return NS_OK;
return IPC_AddClientObserver(aObserver);
}
NS_IMETHODIMP
ipcService::QueryClientByID(PRUint32 clientID,
ipcIClientQueryHandler *handler,
PRBool sync,
PRUint32 *queryID)
ipcService::RemoveClientObserver(ipcIClientObserver *aObserver)
{
if (!mTransport)
return NS_ERROR_NOT_AVAILABLE;
ipcMessage *msg;
msg = new ipcmMessageQueryClientInfo(clientID);
if (!msg)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
rv = mTransport->SendMsg(msg, sync);
if (NS_FAILED(rv)) return rv;
ipcClientQuery *query = new ipcClientQuery(clientID, handler);
if (queryID)
*queryID = query->QueryID();
mQueryQ.Append(query);
return NS_OK;
return IPC_RemoveClientObserver(aObserver);
}
NS_IMETHODIMP
ipcService::CancelQuery(PRUint32 queryID)
ipcService::ResolveClientName(const char *aName, PRUint32 *aID)
{
ipcClientQuery *query = mQueryQ.First();
while (query) {
if (query->QueryID() == queryID) {
query->OnQueryComplete(NS_ERROR_ABORT, NULL);
break;
}
query = query->mNext;
}
return NS_OK;
return IPC_ResolveClientName(aName, aID);
}
NS_IMETHODIMP
ipcService::SetClientObserver(ipcIClientObserver *observer)
ipcService::ClientExists(PRUint32 aClientID, PRBool *aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
return IPC_ClientExists(aClientID, aResult);
}
NS_IMETHODIMP
ipcService::SetMessageObserver(const nsID &target, ipcIMessageObserver *observer)
ipcService::DefineTarget(const nsID &aTarget, ipcIMessageObserver *aObserver)
{
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
nsIDKey key(target);
PRBool sendAdd = PR_TRUE;
ipcIMessageObserver *cobs = (ipcIMessageObserver *) mObserverDB.Get(&key);
if (cobs) {
NS_RELEASE(cobs);
if (!observer) {
mObserverDB.Remove(&key);
//
// send CLIENT_DEL_TARGET
//
mTransport->SendMsg(new ipcmMessageClientDelTarget(target));
return NS_OK;
}
sendAdd = PR_FALSE;
}
if (observer) {
NS_ADDREF(observer);
mObserverDB.Put(&key, observer);
if (sendAdd) {
//
// send CLIENT_ADD_TARGET
//
mTransport->SendMsg(new ipcmMessageClientAddTarget(target));
}
}
return NS_OK;
return IPC_DefineTarget(aTarget, aObserver);
}
NS_IMETHODIMP
ipcService::SendMessage(PRUint32 clientID,
const nsID &target,
const PRUint8 *data,
PRUint32 dataLen,
PRBool sync)
ipcService::SendMessage(PRUint32 aReceiverID, const nsID &aTarget,
const PRUint8 *aData, PRUint32 aDataLen)
{
NS_ENSURE_TRUE(mTransport, NS_ERROR_NOT_INITIALIZED);
if (target.Equals(IPCM_TARGET)) {
NS_ERROR("do not try to talk to the IPCM target directly");
return NS_ERROR_INVALID_ARG;
}
ipcMessage *msg;
if (clientID)
msg = new ipcmMessageForward(clientID, target, (const char *) data, dataLen);
else
msg = new ipcMessage(target, (const char *) data, dataLen);
if (!msg)
return NS_ERROR_OUT_OF_MEMORY;
return mTransport->SendMsg(msg, sync);
return IPC_SendMessage(aReceiverID, aTarget, aData, aDataLen);
}
//-----------------------------------------------------------------------------
// nsIObserver impl
//-----------------------------------------------------------------------------
NS_IMETHODIMP
ipcService::Observe(nsISupports *subject, const char *topic, const PRUnichar *data)
ipcService::WaitMessage(PRUint32 aSenderID, const nsID &aTarget,
ipcIMessageObserver *aObserver,
PRUint32 aTimeout)
{
if (strcmp(topic, "xpcom-shutdown") == 0)
Shutdown();
return NS_OK;
}
//-----------------------------------------------------------------------------
// ipcTransportObserver impl
//-----------------------------------------------------------------------------
void
ipcService::OnConnectionLost()
{
Shutdown();
}
void
ipcService::OnMessageAvailable(const ipcMessage *msg)
{
LOG(("ipcService::OnMessageAvailable [msg=%p]\n", msg));
if (msg->Target().Equals(IPCM_TARGET)) {
//
// all IPCM messages stop here.
//
PRUint32 type = IPCM_GetMsgType(msg);
switch (type) {
case IPCM_MSG_TYPE_CLIENT_ID:
OnIPCMClientID((const ipcmMessageClientID *) msg);
break;
case IPCM_MSG_TYPE_CLIENT_INFO:
OnIPCMClientInfo((const ipcmMessageClientInfo *) msg);
break;
case IPCM_MSG_TYPE_ERROR:
OnIPCMError((const ipcmMessageError *) msg);
break;
}
}
else {
nsIDKey key(msg->Target());
ipcIMessageObserver *observer = (ipcIMessageObserver *) mObserverDB.Get(&key);
if (observer)
observer->OnMessageAvailable(msg->Target(),
(const PRUint8 *) msg->Data(),
msg->DataLen());
}
return IPC_WaitMessage(aSenderID, aTarget, aObserver, PR_MillisecondsToInterval(aTimeout));
}

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -73,6 +73,8 @@ IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg)
// next message sent to the client.
if (msg->TestFlag(IPC_MSG_FLAG_SYNC_QUERY)) {
PR_ASSERT(client->GetExpectsSyncReply() == PR_FALSE);
// XXX shouldn't we remember the TargetID as well, and only set the
// SYNC_REPLY flag on the next message sent to the same TargetID?
client->SetExpectsSyncReply(PR_TRUE);
}
@ -112,6 +114,32 @@ IPC_SendMsg(ipcClient *client, ipcMessage *msg)
return PR_FAILURE;
}
void
IPC_NotifyClientUp(ipcClient *client)
{
// notify modules before other clients
IPC_NotifyModulesClientUp(client);
for (int i=0; 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
//-----------------------------------------------------------------------------

View File

@ -73,4 +73,10 @@ PRStatus IPC_DispatchMsg(ipcClientHandle client, const ipcMessage *msg);
//
PRStatus IPC_SendMsg(ipcClientHandle client, ipcMessage *msg);
//
// dispatch notifications about client connects and disconnects
//
void IPC_NotifyClientUp(ipcClientHandle client);
void IPC_NotifyClientDown(ipcClientHandle client);
#endif // !IPCD_H__

View File

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

View File

@ -74,18 +74,3 @@ interface ipcILockService : nsISupports
*/
void releaseLock(in string aLockName);
};
%{C++
// singleton implementing ipcILockService
#define IPC_LOCKSERVICE_CLASSNAME \
"ipcLockService"
#define IPC_LOCKSERVICE_CONTRACTID \
"@mozilla.org/ipc/lock-service;1"
#define IPC_LOCKSERVICE_CID \
{ /* d9e56bf8-e32e-4b6d-87f1-06d73b0ce7ca */ \
0xd9e56bf8, \
0xe32e, \
0x4b6d, \
{0x87, 0xf1, 0x06, 0xd7, 0x3b, 0x0c, 0xe7, 0xca} \
}
%}

View File

@ -79,7 +79,8 @@ struct ipcLockMsg
PRUint8 *IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen);
//
// unflatten a lock message
// unflatten a lock message. upon return, msg->key points into buf, so
// buf must not be deallocated until after msg is no longer needed.
//
void IPC_UnflattenLockMsg(const PRUint8 *buf, PRUint32 bufLen, ipcLockMsg *msg);

View File

@ -42,29 +42,23 @@
#include "ipcLockProtocol.h"
#include "ipcLog.h"
static NS_DEFINE_IID(kIPCServiceCID, IPC_SERVICE_CID);
static const nsID kLockTargetID = IPC_LOCK_TARGETID;
ipcLockService::ipcLockService()
{
}
ipcLockService::~ipcLockService()
{
}
//-----------------------------------------------------------------------------
nsresult
ipcLockService::Init()
{
nsresult rv;
mIPCService = do_GetService(kIPCServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = IPC_Init();
if (NS_FAILED(rv))
return rv;
return mIPCService->SetMessageObserver(kLockTargetID, this);
return IPC_DefineTarget(kLockTargetID, this);
}
NS_IMPL_ISUPPORTS1(ipcLockService, ipcILockService)
NS_IMPL_ISUPPORTS2(ipcLockService, ipcILockService, ipcIMessageObserver)
NS_IMETHODIMP
ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool waitIfBusy)
@ -82,7 +76,7 @@ ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool
if (!buf)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = mIPCService->SendMessage(0, kLockTargetID, buf, bufLen, (notify == nsnull));
nsresult rv = IPC_SendMessage(0, kLockTargetID, buf, bufLen);
free(buf);
if (NS_FAILED(rv)) {
LOG((" SendMessage failed [rv=%x]\n", rv));
@ -92,9 +86,16 @@ ipcLockService::AcquireLock(const char *lockName, ipcILockNotify *notify, PRBool
if (notify) {
nsCStringKey hashKey(lockName);
mPendingTable.Put(&hashKey, notify);
return NS_OK;
}
return NS_OK;
// block the calling thread until we get a response from the daemon
mSyncLockName = lockName;
rv = IPC_WaitMessage(0, kLockTargetID, nsnull, PR_INTERVAL_NO_TIMEOUT);
mSyncLockName = nsnull;
return NS_FAILED(rv) ? rv : mSyncLockStatus;
}
NS_IMETHODIMP
@ -112,7 +113,7 @@ ipcLockService::ReleaseLock(const char *lockName)
if (!buf)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = mIPCService->SendMessage(0, kLockTargetID, buf, bufLen, PR_FALSE);
nsresult rv = IPC_SendMessage(0, kLockTargetID, buf, bufLen);
free(buf);
if (NS_FAILED(rv)) return rv;
@ -123,12 +124,13 @@ ipcLockService::ReleaseLock(const char *lockName)
}
NS_IMETHODIMP
ipcLockService::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUint32 dataLen)
ipcLockService::OnMessageAvailable(PRUint32 unused, const nsID &target,
const PRUint8 *data, PRUint32 dataLen)
{
ipcLockMsg msg;
IPC_UnflattenLockMsg(data, dataLen, &msg);
LOG(("ipcLockService::OnMessageAvailable [lock=%s opcode=%u]\n", msg.key, msg.opcode));
LOG(("ipcLockService::OnMessageAvailable [lock=%s opcode=%u sync-lock=%s]\n", msg.key, msg.opcode, mSyncLockName));
nsresult status;
if (msg.opcode == IPC_LOCK_OP_STATUS_ACQUIRED)
@ -136,6 +138,16 @@ ipcLockService::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUi
else
status = NS_ERROR_FAILURE;
// handle synchronous waiting case first
if (mSyncLockName) {
if (strcmp(mSyncLockName, msg.key) == 0) {
mSyncLockStatus = status;
return NS_OK;
}
return IPC_WAIT_NEXT_MESSAGE;
}
// otherwise, this is an asynchronous notification
NotifyComplete(msg.key, status);
return NS_OK;
}

View File

@ -39,9 +39,8 @@
#define ipcLockService_h__
#include "ipcILockService.h"
#include "ipcIService.h"
#include "ipcIMessageObserver.h"
#include "ipcList.h"
#include "ipcdclient.h"
#include "nsCOMPtr.h"
#include "nsHashtable.h"
@ -53,18 +52,20 @@ public:
NS_DECL_IPCILOCKSERVICE
NS_DECL_IPCIMESSAGEOBSERVER
ipcLockService();
virtual ~ipcLockService();
nsresult Init();
ipcLockService() : mSyncLockName(nsnull) {}
~ipcLockService() { IPC_Shutdown(); }
NS_HIDDEN_(nsresult) Init();
private:
void NotifyComplete(const char *lockName, nsresult status);
nsCOMPtr<ipcIService> mIPCService;
NS_HIDDEN_(void) NotifyComplete(const char *lockName, nsresult status);
// map from lockname to locknotify for pending notifications
nsSupportsHashtable mPendingTable;
nsSupportsHashtable mPendingTable;
// if non-null, then this is the name of the lock we are trying to
// synchronously acquire.
const char *mSyncLockName;
nsresult mSyncLockStatus;
};
#endif // !ipcLockService_h__

View File

@ -119,66 +119,76 @@ ipcLockModule_AcquireLock(PRUint32 cid, PRUint8 flags, const char *key)
}
}
static void
ipcLockModule_ReleaseLock(PRUint32 cid, const char *key)
static PRBool
ipcLockModule_ReleaseLockHelper(PRUint32 cid, const char *key, ipcLockContext *ctx)
{
printf("$$$ releasing lock [key=%s]\n", key);
PRBool removeEntry = PR_FALSE;
//
// lock is already acquired _or_ maybe client is on the pending list.
//
if (ctx->mOwnerID == cid) {
if (ctx->mNextPending) {
//
// remove this element from the list. since this is the
// first element in the list, instead of removing it we
// shift the data from the next context into this one and
// delete the next context.
//
ipcLockContext *next = ctx->mNextPending;
ctx->mOwnerID = next->mOwnerID;
ctx->mNextPending = next->mNextPending;
delete next;
//
// notify client that it now owns the lock
//
ipcLockModule_Send(ctx->mOwnerID, key, IPC_LOCK_OP_STATUS_ACQUIRED);
}
else {
delete ctx;
removeEntry = PR_TRUE;
}
}
else {
ipcLockContext *prev;
for (;;) {
prev = ctx;
ctx = ctx->mNextPending;
if (!ctx)
break;
if (ctx->mOwnerID == cid) {
// remove ctx from list
prev->mNextPending = ctx->mNextPending;
delete ctx;
break;
}
}
}
return removeEntry;
}
static void
ipcLockModule_ReleaseLock(PRUint32 cid, const char *key)
{
if (!gLockTable)
return;
ipcLockContext *ctx;
ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key);
if (ctx) {
//
// lock is already acquired _or_ maybe client is on the pending list.
//
if (ctx->mOwnerID == cid) {
if (ctx->mNextPending) {
//
// remove this element from the list. since this is the
// first element in the list, instead of removing it we
// shift the data from the next context into this one and
// delete the next context.
//
ipcLockContext *next = ctx->mNextPending;
ctx->mOwnerID = next->mOwnerID;
ctx->mNextPending = next->mNextPending;
delete next;
//
// notify client that it now owns the lock
//
ipcLockModule_Send(ctx->mOwnerID, key, IPC_LOCK_OP_STATUS_ACQUIRED);
}
else {
delete ctx;
PL_HashTableRemove(gLockTable, key);
}
}
else {
ipcLockContext *prev;
for (;;) {
prev = ctx;
ctx = ctx->mNextPending;
if (!ctx)
break;
if (ctx->mOwnerID == cid) {
// remove ctx from list
prev->mNextPending = ctx->mNextPending;
delete ctx;
break;
}
}
}
}
if (ctx && ipcLockModule_ReleaseLockHelper(cid, key, ctx))
PL_HashTableRemove(gLockTable, key);
}
PR_STATIC_CALLBACK(PRIntn)
ipcLockModule_ReleaseByCID(PLHashEntry *he, PRIntn i, void *arg)
{
PRUint32 cid = *(PRUint32 *) arg;
ipcLockModule_ReleaseLock(cid, (const char *) he->key);
ipcLockModule_ReleaseLockHelper(cid, (const char *) he->key,
(ipcLockContext *) he->value);
return HT_ENUMERATE_NEXT;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -161,6 +161,17 @@ public:
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:
void AdvanceHead()
{

View File

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

View File

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

View File

@ -43,16 +43,39 @@ ipcMessage_DWORD_STR::ipcMessage_DWORD_STR(const nsID &target,
const char *second)
{
int sLen = strlen(second);
Init(target, NULL, sizeof(first) + sLen + 1);
SetData(0, (char *) &first, sizeof(first));
SetData(sizeof(first), second, sLen + 1);
Init(target, NULL, 4 + sLen + 1);
SetData(0, (char *) &first, 4);
SetData(4, second, sLen + 1);
}
ipcMessage_DWORD_DWORD_STR::ipcMessage_DWORD_DWORD_STR(const nsID &target,
PRUint32 first,
PRUint32 second,
const char *third)
{
int sLen = strlen(third);
Init(target, NULL, 8 + sLen + 1);
SetData(0, (char *) &first, 4);
SetData(4, (char *) &second, 4);
SetData(8, third, sLen + 1);
}
ipcMessage_DWORD_ID::ipcMessage_DWORD_ID(const nsID &target,
PRUint32 first,
const nsID &second)
{
Init(target, NULL, sizeof(first) + sizeof(nsID));
SetData(0, (char *) &first, sizeof(first));
SetData(sizeof(first), (char *) &second, sizeof(nsID));
Init(target, NULL, 4 + sizeof(nsID));
SetData(0, (char *) &first, 4);
SetData(4, (char *) &second, sizeof(nsID));
}
ipcMessage_DWORD_DWORD_ID::ipcMessage_DWORD_DWORD_ID(const nsID &target,
PRUint32 first,
PRUint32 second,
const nsID &third)
{
Init(target, NULL, 8 + sizeof(nsID));
SetData(0, (char *) &first, 4);
SetData(4, (char *) &second, 4);
SetData(8, (char *) &third, sizeof(nsID));
}

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
{
public:
ipcMessage_DWORD_STR(const nsID &target, PRUint32 first, const char *second);
ipcMessage_DWORD_STR(const nsID &target, PRUint32 first, const char *second) NS_HIDDEN;
PRUint32 First() const
{
@ -90,10 +145,31 @@ public:
}
};
class ipcMessage_DWORD_DWORD_STR : public ipcMessage
{
public:
ipcMessage_DWORD_DWORD_STR(const nsID &target, PRUint32 first, PRUint32 second, const char *second) NS_HIDDEN;
PRUint32 First() const
{
return ((PRUint32 *) Data())[0];
}
PRUint32 Second() const
{
return ((PRUint32 *) Data())[1];
}
const char *Third() const
{
return Data() + 2 * sizeof(PRUint32);
}
};
class ipcMessage_DWORD_ID : public ipcMessage
{
public:
ipcMessage_DWORD_ID(const nsID &target, PRUint32 first, const nsID &second);
ipcMessage_DWORD_ID(const nsID &target, PRUint32 first, const nsID &second) NS_HIDDEN;
PRUint32 First() const
{
@ -106,4 +182,25 @@ public:
}
};
class ipcMessage_DWORD_DWORD_ID : public ipcMessage
{
public:
ipcMessage_DWORD_DWORD_ID(const nsID &target, PRUint32 first, PRUint32 second, const nsID &third) NS_HIDDEN;
PRUint32 First() const
{
return ((PRUint32 *) Data())[0];
}
PRUint32 Second() const
{
return ((PRUint32 *) Data())[1];
}
const nsID &Third() const
{
return * (const nsID *) (Data() + 2 * sizeof(PRUint32));
}
};
#endif // !ipcMessagePrimitives_h__

View File

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

View File

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

View File

@ -41,47 +41,291 @@
#include "ipcMessage.h"
#include "ipcMessagePrimitives.h"
//-----------------------------------------------------------------------------
//
// IPCM (IPC Manager) protocol support
//
// The IPCM message target identifier:
extern const nsID IPCM_TARGET;
enum {
IPCM_MSG_TYPE_PING,
IPCM_MSG_TYPE_ERROR,
IPCM_MSG_TYPE_CLIENT_HELLO,
IPCM_MSG_TYPE_CLIENT_ID,
IPCM_MSG_TYPE_CLIENT_INFO,
IPCM_MSG_TYPE_CLIENT_ADD_NAME,
IPCM_MSG_TYPE_CLIENT_DEL_NAME,
IPCM_MSG_TYPE_CLIENT_ADD_TARGET,
IPCM_MSG_TYPE_CLIENT_DEL_TARGET,
IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME,
IPCM_MSG_TYPE_QUERY_CLIENT_INFO,
// IPCM_MSG_TYPE_QUERY_MODULE, // check if module exists
IPCM_MSG_TYPE_FORWARD,
IPCM_MSG_TYPE_UNKNOWN // unknown message type
//
// Every IPCM message has the following structure:
//
// +-----------------------------------------+
// | (ipc message header) |
// +-----------------------------------------+
// | DWORD : type |
// +-----------------------------------------+
// | DWORD : requestIndex |
// +-----------------------------------------+
// . .
// . (payload) .
// . .
// +-----------------------------------------+
//
// where |type| is an integer uniquely identifying the message. the type is
// composed of a message class identifier and a message number. there are 3
// message classes:
//
// ACK - acknowledging a request
// REQ - making a request
// PSH - providing unrequested, "pushed" information
//
// The requestIndex field is initialized when a request is made. An
// acknowledgement's requestIndex is equal to that of its corresponding
// request message. This enables the requesting side of the message exchange
// to match acknowledgements to requests. The requestIndex field is ignored
// for PSH messages.
//
// The IPCM message class is stored in the most significant byte.
#define IPCM_MSG_CLASS_REQ (1 << 24)
#define IPCM_MSG_CLASS_ACK (2 << 24)
#define IPCM_MSG_CLASS_PSH (4 << 24)
// Requests
#define IPCM_MSG_REQ_PING (IPCM_MSG_CLASS_REQ | 1)
#define IPCM_MSG_REQ_FORWARD (IPCM_MSG_CLASS_REQ | 2)
#define IPCM_MSG_REQ_CLIENT_HELLO (IPCM_MSG_CLASS_REQ | 3)
#define IPCM_MSG_REQ_CLIENT_ADD_NAME (IPCM_MSG_CLASS_REQ | 4)
#define IPCM_MSG_REQ_CLIENT_DEL_NAME (IPCM_MSG_CLASS_REQ | 5)
#define IPCM_MSG_REQ_CLIENT_ADD_TARGET (IPCM_MSG_CLASS_REQ | 6)
#define IPCM_MSG_REQ_CLIENT_DEL_TARGET (IPCM_MSG_CLASS_REQ | 7)
#define IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME (IPCM_MSG_CLASS_REQ | 8)
#define IPCM_MSG_REQ_QUERY_CLIENT_NAMES (IPCM_MSG_CLASS_REQ | 9) // TODO
#define IPCM_MSG_REQ_QUERY_CLIENT_TARGETS (IPCM_MSG_CLASS_REQ | 10) // TODO
// Acknowledgements
#define IPCM_MSG_ACK_RESULT (IPCM_MSG_CLASS_ACK | 1)
#define IPCM_MSG_ACK_CLIENT_ID (IPCM_MSG_CLASS_ACK | 2)
#define IPCM_MSG_ACK_CLIENT_NAMES (IPCM_MSG_CLASS_ACK | 3) // TODO
#define IPCM_MSG_ACK_CLIENT_TARGETS (IPCM_MSG_CLASS_ACK | 4) // TODO
// Push messages
#define IPCM_MSG_PSH_CLIENT_STATE (IPCM_MSG_CLASS_PSH | 1)
#define IPCM_MSG_PSH_FORWARD (IPCM_MSG_CLASS_PSH | 2)
//-----------------------------------------------------------------------------
//
// IPCM header
//
struct ipcmMessageHeader
{
PRUint32 mType;
PRUint32 mRequestIndex;
};
//
// returns IPCM message type.
//
static inline int
IPCM_GetMsgType(const ipcMessage *msg)
IPCM_GetType(const ipcMessage *msg)
{
return ((const ipcMessage_DWORD *) msg)->First();
return ((const ipcmMessageHeader *) msg->Data())->mType;
}
//
// NOTE: this file declares some helper classes that simplify construction
// and parsing of IPCM messages. each class subclasses ipcMessage, but
// adds no additional member variables. operator new should be used
// return IPCM message request index.
//
static inline PRUint32
IPCM_GetRequestIndex(const ipcMessage *msg)
{
return ((const ipcmMessageHeader *) msg->Data())->mRequestIndex;
}
//
// return a request index that is unique to this process.
//
NS_HIDDEN_(PRUint32)
IPCM_NewRequestIndex();
//-----------------------------------------------------------------------------
//
// The IPCM protocol is detailed below:
//
// REQUESTS
//
// req: IPCM_MSG_REQ_PING
// ack: IPCM_MSG_ACK_RESULT
//
// A PING can be sent from either a client to the daemon, or from the daemon
// to a client. The expected acknowledgement is a RESULT message with a status
// code of 0.
//
// This request message has no payload.
//
//
// req: IPCM_MSG_REQ_FORWARD
// ack: IPCM_MSG_ACK_RESULT
//
// A FORWARD is sent when a client wishes to send a message to another client.
// The payload of this message is another message that should be forwarded by
// the daemon's IPCM to the specified client. The expected acknowledgment is
// a RESULT message with a status code indicating success or failure.
//
// When the daemon receives a FORWARD message, it creates a PSH_FORWARD message
// and sends that on to the destination client.
//
// This request message has as its payload:
//
// +-----------------------------------------+
// | DWORD : clientID |
// +-----------------------------------------+
// | (innerMsgHeader) |
// +-----------------------------------------+
// | (innerMsgData) |
// +-----------------------------------------+
//
//
// req: IPCM_MSG_REQ_CLIENT_HELLO
// ack: IPCM_MSG_REQ_CLIENT_ID <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.:
//
// ipcMessage *msg = new ipcmMessageClientHello("foo");
//
// given an arbitrary ipcMessage, it can be parsed using logic similar
// Given an arbitrary ipcMessage, it can be parsed using logic similar
// to the following:
//
// void func(const ipcMessage *unknown)
@ -94,229 +338,162 @@ IPCM_GetMsgType(const ipcMessage *msg)
// }
// }
//
// in other words, these classes are very very lightweight.
//
//
// IPCM_MSG_TYPE_PING
//
// this message may be sent from either the client or the daemon.
// if the daemon receives this message, then it will respond by
// sending back a PING to the client.
//
class ipcmMessagePing : public ipcMessage_DWORD
// REQUESTS
class ipcmMessagePing : public ipcMessage_DWORD_DWORD
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessagePing()
: ipcMessage_DWORD(IPCM_TARGET, MSG_TYPE) {}
: ipcMessage_DWORD_DWORD(
IPCM_TARGET,
IPCM_MSG_REQ_PING,
IPCM_NewRequestIndex()) {}
};
//
// IPCM_MSG_TYPE_ERROR
//
// this message may be sent from the daemon in place of an expected
// result. e.g., if a query fails, the daemon will send an error
// message to indicate the failure.
//
class ipcmMessageError : public ipcMessage_DWORD_DWORD
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageError(PRUint32 reason)
: ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, reason) {}
PRUint32 Reason() const { return Second(); }
};
enum {
IPCM_ERROR_CLIENT_NOT_FOUND = 1
};
//
// IPCM_MSG_TYPE_CLIENT_HELLO
//
// this message is always the first message sent from a client to register
// itself with the daemon. the daemon responds to this message by sending
// the client a CLIENT_ID message informing the client of its client ID.
//
// XXX may want to pass other information here.
//
class ipcmMessageClientHello : public ipcMessage_DWORD
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageClientHello()
: ipcMessage_DWORD(IPCM_TARGET, MSG_TYPE) {}
};
//
// IPCM_MSG_TYPE_CLIENT_ID
//
// this message is sent from the daemon to identify a client's ID.
//
class ipcmMessageClientID : public ipcMessage_DWORD_DWORD
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageClientID(PRUint32 clientID)
: ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, clientID) {}
PRUint32 ClientID() const { return Second(); }
};
//
// IPCM_MSG_TYPE_CLIENT_INFO
//
// this message is sent from the daemon to provide the list of names
// and targets for a particular client.
//
class ipcmMessageClientInfo : public ipcMessage
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageClientInfo(PRUint32 clientID, const char **names, const nsID **targets);
PRUint32 ClientID() const;
PRUint32 NameCount() const;
PRUint32 TargetCount() const;
const char *NextName(const char *name) const;
const nsID *NextTarget(const nsID *target) const;
};
//
// IPCM_MSG_TYPE_CLIENT_ADD_NAME
//
class ipcmMessageClientAddName : public ipcMessage_DWORD_STR
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageClientAddName(const char *name)
: ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {}
const char *Name() const { return Second(); }
};
//
// IPCM_MSG_TYPE_CLIENT_DEL_NAME
//
class ipcmMessageClientDelName : public ipcMessage_DWORD_STR
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageClientDelName(const char *name)
: ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {}
const char *Name() const { return Second(); }
};
//
// IPCM_MSG_TYPE_CLIENT_ADD_TARGET
//
class ipcmMessageClientAddTarget : public ipcMessage_DWORD_ID
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageClientAddTarget(const nsID &target)
: ipcMessage_DWORD_ID(IPCM_TARGET, MSG_TYPE, target) {}
const nsID &Target() const { return Second(); }
};
//
// IPCM_MSG_TYPE_CLIENT_DEL_TARGET
//
class ipcmMessageClientDelTarget : public ipcMessage_DWORD_ID
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageClientDelTarget(const nsID &target)
: ipcMessage_DWORD_ID(IPCM_TARGET, MSG_TYPE, target) {}
const nsID &Target() const { return Second(); }
};
//
// IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME
//
// this message is sent from a client to the daemon to request the ID of the
// client corresponding to the given name. in response the daemon will either
// send a CLIENT_ID or an ERROR message.
//
class ipcmMessageQueryClientByName : public ipcMessage_DWORD_STR
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageQueryClientByName(const char *name)
: ipcMessage_DWORD_STR(IPCM_TARGET, MSG_TYPE, name) {}
const char *Name() const { return Second(); }
};
//
// IPCM_MSG_TYPE_QUERY_CLIENT_INFO
//
// this message is sent from a client to the daemon to request complete
// information about the client corresponding to the given client ID. in
// response the daemon will either send a CLIENT_INFO or an ERROR message.
//
class ipcmMessageQueryClientInfo : public ipcMessage_DWORD_DWORD
{
public:
static const PRUint32 MSG_TYPE;
ipcmMessageQueryClientInfo(PRUint32 clientID)
: ipcMessage_DWORD_DWORD(IPCM_TARGET, MSG_TYPE, clientID) {}
PRUint32 ClientID() const { return Second(); }
};
//
// IPCM_MSG_TYPE_FORWARD
//
// this message is only sent from the client to the daemon. the daemon
// will forward the contained message to the specified client. there
// is no guarantee that the message will be forwarded, and no error will
// be sent to the sender on failure.
//
class ipcmMessageForward : public ipcMessage
{
public:
static const PRUint32 MSG_TYPE;
//
// params:
// clientID - the client to which the message should be forwarded
// target - the message target
// data - the message data
// dataLen - the message data length
//
ipcmMessageForward(PRUint32 clientID,
// @param type the type of this message: IPCM_MSG_{REQ,PSH}_FORWARD
// @param clientID the client id of the sender or receiver
// @param target the message target
// @param data the message data
// @param dataLen the message data length
ipcmMessageForward(PRUint32 type,
PRUint32 clientID,
const nsID &target,
const char *data,
PRUint32 dataLen);
PRUint32 dataLen) NS_HIDDEN;
//
// set inner message data, constrained to the data length passed
// to this class's constructor.
//
void SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen);
NS_HIDDEN_(void) SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen);
PRUint32 DestClientID() const;
const nsID &InnerTarget() const;
const char *InnerData() const;
PRUint32 InnerDataLen() const;
NS_HIDDEN_(PRUint32) ClientID() const;
NS_HIDDEN_(const nsID &) InnerTarget() const;
NS_HIDDEN_(const char *) InnerData() const;
NS_HIDDEN_(PRUint32) InnerDataLen() const;
};
class ipcmMessageClientHello : public ipcMessage_DWORD_DWORD
{
public:
ipcmMessageClientHello()
: ipcMessage_DWORD_DWORD(
IPCM_TARGET,
IPCM_MSG_REQ_CLIENT_HELLO,
IPCM_NewRequestIndex()) {}
};
class ipcmMessageClientAddName : public ipcMessage_DWORD_DWORD_STR
{
public:
ipcmMessageClientAddName(const char *name)
: ipcMessage_DWORD_DWORD_STR(
IPCM_TARGET,
IPCM_MSG_REQ_CLIENT_ADD_NAME,
IPCM_NewRequestIndex(),
name) {}
const char *Name() const { return Third(); }
};
class ipcmMessageClientDelName : public ipcMessage_DWORD_DWORD_STR
{
public:
ipcmMessageClientDelName(const char *name)
: ipcMessage_DWORD_DWORD_STR(
IPCM_TARGET,
IPCM_MSG_REQ_CLIENT_DEL_NAME,
IPCM_NewRequestIndex(),
name) {}
const char *Name() const { return Third(); }
};
class ipcmMessageClientAddTarget : public ipcMessage_DWORD_DWORD_ID
{
public:
ipcmMessageClientAddTarget(const nsID &target)
: ipcMessage_DWORD_DWORD_ID(
IPCM_TARGET,
IPCM_MSG_REQ_CLIENT_ADD_TARGET,
IPCM_NewRequestIndex(),
target) {}
const nsID &Target() const { return Third(); }
};
class ipcmMessageClientDelTarget : public ipcMessage_DWORD_DWORD_ID
{
public:
ipcmMessageClientDelTarget(const nsID &target)
: ipcMessage_DWORD_DWORD_ID(
IPCM_TARGET,
IPCM_MSG_REQ_CLIENT_ADD_TARGET,
IPCM_NewRequestIndex(),
target) {}
const nsID &Target() const { return Third(); }
};
class ipcmMessageQueryClientByName : public ipcMessage_DWORD_DWORD_STR
{
public:
ipcmMessageQueryClientByName(const char *name)
: ipcMessage_DWORD_DWORD_STR(
IPCM_TARGET,
IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME,
IPCM_NewRequestIndex(),
name) {}
const char *Name() const { return Third(); }
PRUint32 RequestIndex() const { return Second(); }
};
// ACKNOWLEDGEMENTS
class ipcmMessageResult : public ipcMessage_DWORD_DWORD_DWORD
{
public:
ipcmMessageResult(PRUint32 requestIndex, PRInt32 status)
: ipcMessage_DWORD_DWORD_DWORD(
IPCM_TARGET,
IPCM_MSG_ACK_RESULT,
requestIndex,
(PRUint32) status) {}
PRInt32 Status() const { return (PRInt32) Third(); }
};
class ipcmMessageClientID : public ipcMessage_DWORD_DWORD_DWORD
{
public:
ipcmMessageClientID(PRUint32 requestIndex, PRUint32 clientID)
: ipcMessage_DWORD_DWORD_DWORD(
IPCM_TARGET,
IPCM_MSG_ACK_CLIENT_ID,
requestIndex,
clientID) {}
PRUint32 ClientID() const { return Third(); }
};
// PUSH MESSAGES
class ipcmMessageClientState : public ipcMessage_DWORD_DWORD_DWORD_DWORD
{
public:
ipcmMessageClientState(PRUint32 clientID, PRUint32 clientStatus)
: ipcMessage_DWORD_DWORD_DWORD_DWORD(
IPCM_TARGET,
IPCM_MSG_PSH_CLIENT_STATE,
0,
clientID,
clientStatus) {}
PRUint32 ClientID() const { return Third(); }
PRUint32 ClientState() const { return Fourth(); }
};
#endif // !ipcm_h__

View File

@ -40,6 +40,8 @@
#include "ipcIClientQueryHandler.h"
#include "ipcILockService.h"
#include "ipcILockNotify.h"
#include "ipcCID.h"
#include "ipcLockCID.h"
#include "nsIEventQueueService.h"
#include "nsIServiceManager.h"
@ -75,7 +77,6 @@ static const nsID kTestTargetID =
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static nsIEventQueue* gEventQ = nsnull;
static PRBool gKeepRunning = PR_TRUE;
//static PRInt32 gMsgCount = 0;
static ipcIService *gIpcServ = nsnull;
static ipcILockService *gIpcLockServ = nsnull;
@ -84,8 +85,19 @@ SendMsg(ipcIService *ipc, PRUint32 cID, const nsID &target, const char *data, PR
{
printf("*** sending message: [to-client=%u dataLen=%u]\n", cID, dataLen);
ipc->SendMessage(cID, target, (const PRUint8 *) data, dataLen, sync);
// gMsgCount++;
nsresult rv;
rv = ipc->SendMessage(cID, target, (const PRUint8 *) data, dataLen);
if (NS_FAILED(rv)) {
printf("*** sending message failed: rv=%x\n", rv);
return;
}
if (sync) {
rv = ipc->WaitMessage(cID, target, nsnull, PR_UINT32_MAX);
if (NS_FAILED(rv))
printf("*** waiting for message failed: rv=%x\n", rv);
}
}
//-----------------------------------------------------------------------------
@ -95,25 +107,19 @@ class myIpcMessageObserver : public ipcIMessageObserver
public:
NS_DECL_ISUPPORTS
NS_DECL_IPCIMESSAGEOBSERVER
myIpcMessageObserver() {}
};
NS_IMPL_ISUPPORTS1(myIpcMessageObserver, ipcIMessageObserver)
NS_IMETHODIMP
myIpcMessageObserver::OnMessageAvailable(const nsID &target, const PRUint8 *data, PRUint32 dataLen)
myIpcMessageObserver::OnMessageAvailable(PRUint32 sender, const nsID &target, const PRUint8 *data, PRUint32 dataLen)
{
printf("*** got message: [%s]\n", (const char *) data);
// if (--gMsgCount == 0)
// gKeepRunning = PR_FALSE;
printf("*** got message: [sender=%u data=%s]\n", sender, (const char *) data);
return NS_OK;
}
//-----------------------------------------------------------------------------
#if 0
class myIpcClientQueryHandler : public ipcIClientQueryHandler
{
public:
@ -160,6 +166,7 @@ myIpcClientQueryHandler::OnQueryComplete(PRUint32 aQueryID,
return NS_OK;
}
#endif
//-----------------------------------------------------------------------------
@ -205,16 +212,17 @@ int main(int argc, char **argv)
rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ);
RETURN_IF_FAILED(rv, "GetThreadEventQueue");
printf("*** getting ipc service\n");
nsCOMPtr<ipcIService> ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv));
RETURN_IF_FAILED(rv, "do_GetService(ipcServ)");
NS_ADDREF(gIpcServ = ipcServ);
if (argc > 1) {
printf("*** using client name [%s]\n", argv[1]);
gIpcServ->AddClientName(argv[1]);
gIpcServ->AddName(argv[1]);
}
ipcServ->SetMessageObserver(kTestTargetID, new myIpcMessageObserver());
ipcServ->DefineTarget(kTestTargetID, new myIpcMessageObserver());
const char data[] =
"01 this is a really long message.\n"
@ -279,9 +287,18 @@ int main(int argc, char **argv)
"60 this is a really long message.\n";
SendMsg(ipcServ, 0, kTestTargetID, data, sizeof(data), PR_TRUE);
PRUint32 queryID;
nsCOMPtr<ipcIClientQueryHandler> handler(new myIpcClientQueryHandler());
ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID);
// PRUint32 queryID;
// nsCOMPtr<ipcIClientQueryHandler> handler(new myIpcClientQueryHandler());
// ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID);
PRUint32 foopyID;
nsresult foopyRv = ipcServ->ResolveClientName("foopy", &foopyID);
printf("*** query for 'foopy' returned [rv=%x id=%u]\n", foopyRv, foopyID);
if (NS_SUCCEEDED(foopyRv)) {
const char hello[] = "hello friend!";
SendMsg(ipcServ, foopyID, kTestTargetID, hello, sizeof(hello));
}
//
// test lock service