1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is Mozilla IPC.
16
* The Initial Developer of the Original Code is
17
* Netscape Communications Corporation.
18
* Portions created by the Initial Developer are Copyright (C) 2002
19
* the Initial Developer. All Rights Reserved.
22
* Darin Fisher <darin@netscape.com>
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the MPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the MPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
41
#include "ipcMessage.h"
42
#include "ipcMessagePrimitives.h"
44
//-----------------------------------------------------------------------------
47
// IPCM (IPC Manager) protocol support
50
// The IPCM message target identifier:
51
extern const nsID IPCM_TARGET;
54
// Every IPCM message has the following structure:
56
// +-----------------------------------------+
57
// | (ipc message header) |
58
// +-----------------------------------------+
60
// +-----------------------------------------+
61
// | DWORD : requestIndex |
62
// +-----------------------------------------+
66
// +-----------------------------------------+
68
// where |type| is an integer uniquely identifying the message. the type is
69
// composed of a message class identifier and a message number. there are 3
72
// ACK - acknowledging a request
73
// REQ - making a request
74
// PSH - providing unrequested, "pushed" information
76
// The requestIndex field is initialized when a request is made. An
77
// acknowledgement's requestIndex is equal to that of its corresponding
78
// request message. This enables the requesting side of the message exchange
79
// to match acknowledgements to requests. The requestIndex field is ignored
83
// The IPCM message class is stored in the most significant byte.
84
#define IPCM_MSG_CLASS_REQ (1 << 24)
85
#define IPCM_MSG_CLASS_ACK (2 << 24)
86
#define IPCM_MSG_CLASS_PSH (4 << 24)
89
#define IPCM_MSG_REQ_PING (IPCM_MSG_CLASS_REQ | 1)
90
#define IPCM_MSG_REQ_FORWARD (IPCM_MSG_CLASS_REQ | 2)
91
#define IPCM_MSG_REQ_CLIENT_HELLO (IPCM_MSG_CLASS_REQ | 3)
92
#define IPCM_MSG_REQ_CLIENT_ADD_NAME (IPCM_MSG_CLASS_REQ | 4)
93
#define IPCM_MSG_REQ_CLIENT_DEL_NAME (IPCM_MSG_CLASS_REQ | 5)
94
#define IPCM_MSG_REQ_CLIENT_ADD_TARGET (IPCM_MSG_CLASS_REQ | 6)
95
#define IPCM_MSG_REQ_CLIENT_DEL_TARGET (IPCM_MSG_CLASS_REQ | 7)
96
#define IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME (IPCM_MSG_CLASS_REQ | 8)
97
#define IPCM_MSG_REQ_QUERY_CLIENT_NAMES (IPCM_MSG_CLASS_REQ | 9) // TODO
98
#define IPCM_MSG_REQ_QUERY_CLIENT_TARGETS (IPCM_MSG_CLASS_REQ | 10) // TODO
101
#define IPCM_MSG_ACK_RESULT (IPCM_MSG_CLASS_ACK | 1)
102
#define IPCM_MSG_ACK_CLIENT_ID (IPCM_MSG_CLASS_ACK | 2)
103
#define IPCM_MSG_ACK_CLIENT_NAMES (IPCM_MSG_CLASS_ACK | 3) // TODO
104
#define IPCM_MSG_ACK_CLIENT_TARGETS (IPCM_MSG_CLASS_ACK | 4) // TODO
107
#define IPCM_MSG_PSH_CLIENT_STATE (IPCM_MSG_CLASS_PSH | 1)
108
#define IPCM_MSG_PSH_FORWARD (IPCM_MSG_CLASS_PSH | 2)
110
//-----------------------------------------------------------------------------
115
struct ipcmMessageHeader
118
PRUint32 mRequestIndex;
122
// returns IPCM message type.
125
IPCM_GetType(const ipcMessage *msg)
127
return ((const ipcmMessageHeader *) msg->Data())->mType;
131
// return IPCM message request index.
133
static inline PRUint32
134
IPCM_GetRequestIndex(const ipcMessage *msg)
136
return ((const ipcmMessageHeader *) msg->Data())->mRequestIndex;
140
// return a request index that is unique to this process.
143
IPCM_NewRequestIndex();
145
//-----------------------------------------------------------------------------
148
// The IPCM protocol is detailed below:
154
// req: IPCM_MSG_REQ_PING
155
// ack: IPCM_MSG_ACK_RESULT
157
// A PING can be sent from either a client to the daemon, or from the daemon
158
// to a client. The expected acknowledgement is a RESULT message with a status
161
// This request message has no payload.
165
// req: IPCM_MSG_REQ_FORWARD
166
// ack: IPCM_MSG_ACK_RESULT
168
// A FORWARD is sent when a client wishes to send a message to another client.
169
// The payload of this message is another message that should be forwarded by
170
// the daemon's IPCM to the specified client. The expected acknowledgment is
171
// a RESULT message with a status code indicating success or failure.
173
// When the daemon receives a FORWARD message, it creates a PSH_FORWARD message
174
// and sends that on to the destination client.
176
// This request message has as its payload:
178
// +-----------------------------------------+
179
// | DWORD : clientID |
180
// +-----------------------------------------+
181
// | (innerMsgHeader) |
182
// +-----------------------------------------+
183
// | (innerMsgData) |
184
// +-----------------------------------------+
188
// req: IPCM_MSG_REQ_CLIENT_HELLO
189
// ack: IPCM_MSG_REQ_CLIENT_ID <or> IPCM_MSG_REQ_RESULT
191
// A CLIENT_HELLO is sent when a client connects to the IPC daemon. The
192
// expected acknowledgement is a CLIENT_ID message informing the new client of
193
// its ClientID. If for some reason the IPC daemon cannot accept the new
194
// client, it returns a RESULT message with a failure status code.
196
// This request message has no payload.
200
// req: IPCM_MSG_REQ_CLIENT_ADD_NAME
201
// ack: IPCM_MSG_ACK_RESULT
203
// A CLIENT_ADD_NAME is sent when a client wishes to register an additional
204
// name for itself. The expected acknowledgement is a RESULT message with a
205
// status code indicating success or failure.
207
// This request message has as its payload a null-terminated ASCII character
208
// string indicating the name of the client.
212
// req: IPCM_MSG_REQ_CLIENT_DEL_NAME
213
// ack: IPCM_MSG_ACK_RESULT
215
// A CLIENT_DEL_NAME is sent when a client wishes to unregister a name that it
216
// has registered. The expected acknowledgement is a RESULT message with a
217
// status code indicating success or failure.
219
// This request message has as its payload a null-terminated ASCII character
220
// string indicating the name of the client.
224
// req: IPCM_MSG_REQ_CLIENT_ADD_TARGET
225
// ack: IPCM_MSG_ACK_RESULT
227
// A CLIENT_ADD_TARGET is sent when a client wishes to register an additional
228
// target that it supports. The expected acknowledgement is a RESULT message
229
// with a status code indicating success or failure.
231
// This request message has as its payload a 128-bit UUID indicating the
236
// req: IPCM_MSG_REQ_CLIENT_DEL_TARGET
237
// ack: IPCM_MSG_ACK_RESULT
239
// A CLIENT_DEL_TARGET is sent when a client wishes to unregister a target
240
// that it has registered. The expected acknowledgement is a RESULT message
241
// with a status code indicating success or failure.
243
// This request message has as its payload a 128-bit UUID indicating the
248
// req: IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME
249
// ack: IPCM_MSG_ACK_CLIENT_ID <or> IPCM_MSG_ACK_RESULT
251
// A QUERY_CLIENT_BY_NAME may be sent by a client to discover the client that
252
// is known by a common name. If more than one client matches the name, then
253
// only the ID of the more recently registered client is returned. The
254
// expected acknowledgement is a CLIENT_ID message carrying the ID of the
255
// corresponding client. If no client matches the given name or if some error
256
// occurs, then a RESULT message with a failure status code is returned.
258
// This request message has as its payload a null-terminated ASCII character
259
// string indicating the client name to query.
265
// ack: IPCM_MSG_ACK_RESULT
267
// This acknowledgement is returned to indicate a success or failure status.
269
// The payload consists of a single DWORD value.
271
// Possible status codes are listed below (negative values indicate failure
274
#define IPCM_OK 0 // success: generic
275
#define IPCM_ERROR_GENERIC -1 // failure: generic
276
#define IPCM_ERROR_NO_CLIENT -2 // failure: client does not exist
279
// ack: IPCM_MSG_ACK_CLIENT_ID
281
// This acknowledgement is returned to specify a client ID.
283
// The payload consists of a single DWORD value.
289
// psh: ICPM_MSG_PSH_CLIENT_STATE
291
// This message is sent to clients to indicate the status of other clients.
293
// The payload consists of:
295
// +-----------------------------------------+
296
// | DWORD : clientID |
297
// +-----------------------------------------+
298
// | DWORD : clientState |
299
// +-----------------------------------------+
301
// where, clientState is one of the following values indicating whether the
302
// client has recently connected (up) or disconnected (down):
304
#define IPCM_CLIENT_STATE_UP 1
305
#define IPCM_CLIENT_STATE_DOWN 2
308
// psh: IPCM_MSG_PSH_FORWARD
310
// This message is sent by the daemon to a client on behalf of another client.
311
// The recipient is expected to unpack the contained message and process it.
313
// The payload of this message matches the payload of IPCM_MSG_REQ_FORWARD,
314
// with the exception that the clientID field is set to the clientID of the
315
// sender of the IPCM_MSG_REQ_FORWARD message.
318
//-----------------------------------------------------------------------------
321
// NOTE: This file declares some helper classes that simplify constructing
322
// and parsing IPCM messages. Each class subclasses ipcMessage, but
323
// adds no additional member variables. |operator new| should be used
324
// to allocate one of the IPCM helper classes, e.g.:
326
// ipcMessage *msg = new ipcmMessageClientHello("foo");
328
// Given an arbitrary ipcMessage, it can be parsed using logic similar
331
// void func(const ipcMessage *unknown)
333
// if (unknown->Topic().Equals(IPCM_TARGET)) {
334
// if (IPCM_GetMsgType(unknown) == IPCM_MSG_TYPE_CLIENT_ID) {
335
// ipcMessageCast<ipcmMessageClientID> msg(unknown);
336
// printf("Client ID: %u\n", msg->ClientID());
344
class ipcmMessagePing : public ipcMessage_DWORD_DWORD
348
: ipcMessage_DWORD_DWORD(
351
IPCM_NewRequestIndex()) {}
354
class ipcmMessageForward : public ipcMessage
357
// @param type the type of this message: IPCM_MSG_{REQ,PSH}_FORWARD
358
// @param clientID the client id of the sender or receiver
359
// @param target the message target
360
// @param data the message data
361
// @param dataLen the message data length
362
ipcmMessageForward(PRUint32 type,
366
PRUint32 dataLen) NS_HIDDEN;
368
// set inner message data, constrained to the data length passed
369
// to this class's constructor.
370
NS_HIDDEN_(void) SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen);
372
NS_HIDDEN_(PRUint32) ClientID() const;
373
NS_HIDDEN_(const nsID &) InnerTarget() const;
374
NS_HIDDEN_(const char *) InnerData() const;
375
NS_HIDDEN_(PRUint32) InnerDataLen() const;
378
class ipcmMessageClientHello : public ipcMessage_DWORD_DWORD
381
ipcmMessageClientHello()
382
: ipcMessage_DWORD_DWORD(
384
IPCM_MSG_REQ_CLIENT_HELLO,
385
IPCM_NewRequestIndex()) {}
388
class ipcmMessageClientAddName : public ipcMessage_DWORD_DWORD_STR
391
ipcmMessageClientAddName(const char *name)
392
: ipcMessage_DWORD_DWORD_STR(
394
IPCM_MSG_REQ_CLIENT_ADD_NAME,
395
IPCM_NewRequestIndex(),
398
const char *Name() const { return Third(); }
401
class ipcmMessageClientDelName : public ipcMessage_DWORD_DWORD_STR
404
ipcmMessageClientDelName(const char *name)
405
: ipcMessage_DWORD_DWORD_STR(
407
IPCM_MSG_REQ_CLIENT_DEL_NAME,
408
IPCM_NewRequestIndex(),
411
const char *Name() const { return Third(); }
414
class ipcmMessageClientAddTarget : public ipcMessage_DWORD_DWORD_ID
417
ipcmMessageClientAddTarget(const nsID &target)
418
: ipcMessage_DWORD_DWORD_ID(
420
IPCM_MSG_REQ_CLIENT_ADD_TARGET,
421
IPCM_NewRequestIndex(),
424
const nsID &Target() const { return Third(); }
427
class ipcmMessageClientDelTarget : public ipcMessage_DWORD_DWORD_ID
430
ipcmMessageClientDelTarget(const nsID &target)
431
: ipcMessage_DWORD_DWORD_ID(
433
IPCM_MSG_REQ_CLIENT_ADD_TARGET,
434
IPCM_NewRequestIndex(),
437
const nsID &Target() const { return Third(); }
440
class ipcmMessageQueryClientByName : public ipcMessage_DWORD_DWORD_STR
443
ipcmMessageQueryClientByName(const char *name)
444
: ipcMessage_DWORD_DWORD_STR(
446
IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME,
447
IPCM_NewRequestIndex(),
450
const char *Name() const { return Third(); }
451
PRUint32 RequestIndex() const { return Second(); }
456
class ipcmMessageResult : public ipcMessage_DWORD_DWORD_DWORD
459
ipcmMessageResult(PRUint32 requestIndex, PRInt32 status)
460
: ipcMessage_DWORD_DWORD_DWORD(
464
(PRUint32) status) {}
466
PRInt32 Status() const { return (PRInt32) Third(); }
469
class ipcmMessageClientID : public ipcMessage_DWORD_DWORD_DWORD
472
ipcmMessageClientID(PRUint32 requestIndex, PRUint32 clientID)
473
: ipcMessage_DWORD_DWORD_DWORD(
475
IPCM_MSG_ACK_CLIENT_ID,
479
PRUint32 ClientID() const { return Third(); }
484
class ipcmMessageClientState : public ipcMessage_DWORD_DWORD_DWORD_DWORD
487
ipcmMessageClientState(PRUint32 clientID, PRUint32 clientStatus)
488
: ipcMessage_DWORD_DWORD_DWORD_DWORD(
490
IPCM_MSG_PSH_CLIENT_STATE,
495
PRUint32 ClientID() const { return Third(); }
496
PRUint32 ClientState() const { return Fourth(); }