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(); }