xref: /haiku/src/kits/app/Messenger.cpp (revision 4ceb1e519c0447147b1d8b54a324bb7fedd3a606)
152a38012Sejakowatz  //------------------------------------------------------------------------------
21771f7aeSAxel Dörfler //	Copyright (c) 2001-2005, Haiku
352a38012Sejakowatz //
452a38012Sejakowatz //	Permission is hereby granted, free of charge, to any person obtaining a
552a38012Sejakowatz //	copy of this software and associated documentation files (the "Software"),
652a38012Sejakowatz //	to deal in the Software without restriction, including without limitation
752a38012Sejakowatz //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
852a38012Sejakowatz //	and/or sell copies of the Software, and to permit persons to whom the
952a38012Sejakowatz //	Software is furnished to do so, subject to the following conditions:
1052a38012Sejakowatz //
1152a38012Sejakowatz //	The above copyright notice and this permission notice shall be included in
1252a38012Sejakowatz //	all copies or substantial portions of the Software.
1352a38012Sejakowatz //
1452a38012Sejakowatz //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1552a38012Sejakowatz //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1652a38012Sejakowatz //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1752a38012Sejakowatz //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1852a38012Sejakowatz //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1952a38012Sejakowatz //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2052a38012Sejakowatz //	DEALINGS IN THE SOFTWARE.
2152a38012Sejakowatz //
2252a38012Sejakowatz //	File Name:		Messenger.h
2352a38012Sejakowatz //	Author:			Ingo Weinhold (bonefish@users.sf.net)
2452a38012Sejakowatz //	Description:	BMessenger delivers messages to local or remote targets.
2552a38012Sejakowatz //------------------------------------------------------------------------------
2652a38012Sejakowatz 
2752a38012Sejakowatz // debugging
2852a38012Sejakowatz //#define DBG(x) x
2952a38012Sejakowatz #define DBG(x)
3052a38012Sejakowatz #define OUT	printf
3152a38012Sejakowatz 
3252a38012Sejakowatz // Standard Includes -----------------------------------------------------------
3352a38012Sejakowatz #include <new>
3452a38012Sejakowatz #include <stdio.h>
359e9f5a1aSIngo Weinhold #include <string.h>
3652a38012Sejakowatz 
3752a38012Sejakowatz // System Includes -------------------------------------------------------------
3852a38012Sejakowatz #include <Application.h>
3952a38012Sejakowatz #include <Handler.h>
4052a38012Sejakowatz #include <Looper.h>
41e1f41e5dSIngo Weinhold #include <LooperList.h>
4252a38012Sejakowatz #include <Message.h>
4352a38012Sejakowatz #include <Messenger.h>
4452a38012Sejakowatz #include <OS.h>
453b044715SIngo Weinhold #include <Roster.h>
4694b98dffSIngo Weinhold #include <TokenSpace.h>
4752a38012Sejakowatz 
4852a38012Sejakowatz // Project Includes ------------------------------------------------------------
492be975a1Sejakowatz #include <AppMisc.h>
502be975a1Sejakowatz #include <MessageUtils.h>
5137faaadeSIngo Weinhold #include "ObjectLocker.h"
5252a38012Sejakowatz #include "TokenSpace.h"
5352a38012Sejakowatz 
54cf10934eSMichael Lotz #ifdef USING_MESSAGE4
55cf10934eSMichael Lotz #include <MessagePrivate.h>
56cf10934eSMichael Lotz #endif
57cf10934eSMichael Lotz 
5852a38012Sejakowatz // Local Includes --------------------------------------------------------------
5952a38012Sejakowatz 
6052a38012Sejakowatz // Local Defines ---------------------------------------------------------------
6152a38012Sejakowatz 
6252a38012Sejakowatz // Globals ---------------------------------------------------------------------
6352a38012Sejakowatz 
6452a38012Sejakowatz using BPrivate::gDefaultTokens;
6537faaadeSIngo Weinhold using BPrivate::gLooperList;
6637faaadeSIngo Weinhold using BPrivate::BLooperList;
6737faaadeSIngo Weinhold using BPrivate::BObjectLocker;
6852a38012Sejakowatz 
6952a38012Sejakowatz enum {
7052a38012Sejakowatz 	NOT_IMPLEMENTED	= B_ERROR,
7152a38012Sejakowatz };
7252a38012Sejakowatz 
7352a38012Sejakowatz 
7452a38012Sejakowatz /*!	\brief Creates an unitialized BMessenger.
7552a38012Sejakowatz */
7652a38012Sejakowatz BMessenger::BMessenger()
77*4ceb1e51SAxel Dörfler 	:
78*4ceb1e51SAxel Dörfler 	fPort(-1),
7994b98dffSIngo Weinhold 	fHandlerToken(B_NULL_TOKEN),
80*4ceb1e51SAxel Dörfler 	fTeam(-1)
8152a38012Sejakowatz {
8252a38012Sejakowatz }
8352a38012Sejakowatz 
84*4ceb1e51SAxel Dörfler 
8552a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to target the already
8652a38012Sejakowatz 	running application identified by its signature and/or team ID.
8752a38012Sejakowatz 
8852a38012Sejakowatz 	When only a signature is given, and multiple instances of the application
8952a38012Sejakowatz 	are running it is undeterminate which one is chosen as the target. In case
9052a38012Sejakowatz 	only a team ID is passed, the target application is identified uniquely.
9152a38012Sejakowatz 	If both are supplied, the application identified by the team ID must have
9252a38012Sejakowatz 	a matching signature, otherwise the initilization fails.
9352a38012Sejakowatz 
9452a38012Sejakowatz 	\param signature The target application's signature. May be \c NULL.
9552a38012Sejakowatz 	\param team The target application's team ID. May be < 0.
9652a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
9752a38012Sejakowatz 		   the result of the initialization is written.
9852a38012Sejakowatz */
9952a38012Sejakowatz BMessenger::BMessenger(const char *signature, team_id team, status_t *result)
100*4ceb1e51SAxel Dörfler 	:
101*4ceb1e51SAxel Dörfler 	fPort(-1),
10294b98dffSIngo Weinhold 	fHandlerToken(B_NULL_TOKEN),
103*4ceb1e51SAxel Dörfler 	fTeam(-1)
10452a38012Sejakowatz {
105*4ceb1e51SAxel Dörfler 	_InitData(signature, team, result);
10652a38012Sejakowatz }
10752a38012Sejakowatz 
108*4ceb1e51SAxel Dörfler 
10952a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to target the local
11052a38012Sejakowatz 	BHandler and/or BLooper.
11152a38012Sejakowatz 
11252a38012Sejakowatz 	When a \c NULL handler is supplied, the preferred handler in the given
11352a38012Sejakowatz 	looper is targeted. If no looper is supplied the looper the given handler
11452a38012Sejakowatz 	belongs to is used -- that means in particular, that the handler must
11552a38012Sejakowatz 	already belong to a looper. If both are supplied the handler must actually
11652a38012Sejakowatz 	belong to looper.
11752a38012Sejakowatz 
11852a38012Sejakowatz 	\param handler The target handler. May be \c NULL.
11952a38012Sejakowatz 	\param looper The target looper. May be \c NULL.
12052a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
12152a38012Sejakowatz 		   the result of the initialization is written.
12252a38012Sejakowatz */
12352a38012Sejakowatz BMessenger::BMessenger(const BHandler* handler, const BLooper* looper,
124*4ceb1e51SAxel Dörfler 	status_t* _result)
125*4ceb1e51SAxel Dörfler 	:
126*4ceb1e51SAxel Dörfler 	fPort(-1),
12794b98dffSIngo Weinhold 	fHandlerToken(B_NULL_TOKEN),
128*4ceb1e51SAxel Dörfler 	fTeam(-1)
12952a38012Sejakowatz {
13052a38012Sejakowatz 	status_t error = (handler || looper ? B_OK : B_BAD_VALUE);
13152a38012Sejakowatz 	if (error == B_OK) {
13252a38012Sejakowatz 		if (handler) {
13352a38012Sejakowatz 			// BHandler is given, check/retrieve the looper.
13452a38012Sejakowatz 			if (looper) {
13552a38012Sejakowatz 				if (handler->Looper() != looper)
13652a38012Sejakowatz 					error = B_MISMATCHED_VALUES;
13752a38012Sejakowatz 			} else {
13852a38012Sejakowatz 				looper = handler->Looper();
13952a38012Sejakowatz 				if (looper == NULL)
14052a38012Sejakowatz 					error = B_MISMATCHED_VALUES;
14152a38012Sejakowatz 			}
14237faaadeSIngo Weinhold 		}
14352a38012Sejakowatz 		// set port, token,...
14452a38012Sejakowatz 		if (error == B_OK) {
14537faaadeSIngo Weinhold 			BObjectLocker<BLooperList> locker(gLooperList);
14637faaadeSIngo Weinhold 			if (locker.IsLocked() && gLooperList.IsLooperValid(looper)) {
14752a38012Sejakowatz 				fPort = looper->fMsgPort;
14894b98dffSIngo Weinhold 				fHandlerToken = (handler
14994b98dffSIngo Weinhold 					? _get_object_token_(handler) : B_PREFERRED_TOKEN);
15037faaadeSIngo Weinhold 				fTeam = looper->Team();
15137faaadeSIngo Weinhold 			} else
15237faaadeSIngo Weinhold 				error = B_BAD_VALUE;
15352a38012Sejakowatz 		}
15452a38012Sejakowatz 	}
155*4ceb1e51SAxel Dörfler 	if (_result)
156*4ceb1e51SAxel Dörfler 		*_result = error;
15752a38012Sejakowatz }
15852a38012Sejakowatz 
159*4ceb1e51SAxel Dörfler 
16052a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to have the same target
16152a38012Sejakowatz 	as the supplied messemger.
16252a38012Sejakowatz 
16352a38012Sejakowatz 	\param from The messenger to be copied.
16452a38012Sejakowatz */
16552a38012Sejakowatz BMessenger::BMessenger(const BMessenger& from)
166*4ceb1e51SAxel Dörfler 	:
167*4ceb1e51SAxel Dörfler 	fPort(from.fPort),
16852a38012Sejakowatz 	fHandlerToken(from.fHandlerToken),
169*4ceb1e51SAxel Dörfler 	fTeam(from.fTeam)
17052a38012Sejakowatz {
17152a38012Sejakowatz }
17252a38012Sejakowatz 
173*4ceb1e51SAxel Dörfler 
17452a38012Sejakowatz /*!	\brief Frees all resources associated with this object.
17552a38012Sejakowatz */
17652a38012Sejakowatz BMessenger::~BMessenger()
17752a38012Sejakowatz {
17852a38012Sejakowatz }
17952a38012Sejakowatz 
18052a38012Sejakowatz 
181*4ceb1e51SAxel Dörfler //	#pragma mark - Target
18252a38012Sejakowatz 
183*4ceb1e51SAxel Dörfler 
18452a38012Sejakowatz /*!	\brief Returns whether or not the messenger's target lives within the team
18552a38012Sejakowatz 	of the caller.
18652a38012Sejakowatz 
18752a38012Sejakowatz 	\return \c true, if the object is properly initialized and its target
18852a38012Sejakowatz 			lives within the caller's team, \c false otherwise.
18952a38012Sejakowatz */
19052a38012Sejakowatz bool
19152a38012Sejakowatz BMessenger::IsTargetLocal() const
19252a38012Sejakowatz {
19352a38012Sejakowatz 	thread_info info;
194*4ceb1e51SAxel Dörfler 	return get_thread_info(find_thread(NULL), &info) == B_OK
195*4ceb1e51SAxel Dörfler 		&& fTeam == info.team;
19652a38012Sejakowatz }
19752a38012Sejakowatz 
198*4ceb1e51SAxel Dörfler 
19952a38012Sejakowatz /*!	\brief Returns the handler and looper targeted by the messenger, if the
20052a38012Sejakowatz 	target is local.
20152a38012Sejakowatz 
20252a38012Sejakowatz 	The handler is returned directly, the looper by reference. If both are
20352a38012Sejakowatz 	\c NULL, the object is either not properly initialized, the target
20452a38012Sejakowatz 	objects have been deleted or the target is remote. If only the returned
20552a38012Sejakowatz 	handler is \c NULL, either the looper's preferred handler is targeted or
20652a38012Sejakowatz 	the handler has been deleted.
20752a38012Sejakowatz 
20852a38012Sejakowatz 	\param looper A pointer to a pre-allocated BLooper pointer into which
20952a38012Sejakowatz 		   the pointer to the targeted looper is written.
21052a38012Sejakowatz 	\return The BHandler targeted by the messenger.
21152a38012Sejakowatz */
21252a38012Sejakowatz BHandler *
213*4ceb1e51SAxel Dörfler BMessenger::Target(BLooper** _looper) const
21452a38012Sejakowatz {
21552a38012Sejakowatz 	BHandler *handler = NULL;
216*4ceb1e51SAxel Dörfler 	if (IsTargetLocal() && fHandlerToken > B_NULL_TOKEN) {
21752a38012Sejakowatz 		gDefaultTokens.GetToken(fHandlerToken, B_HANDLER_TOKEN,
21852a38012Sejakowatz 			(void**)&handler);
219*4ceb1e51SAxel Dörfler 		if (_looper)
220*4ceb1e51SAxel Dörfler 			*_looper = BPrivate::gLooperList.LooperForPort(fPort);
221*4ceb1e51SAxel Dörfler 	} else if (_looper)
222*4ceb1e51SAxel Dörfler 		*_looper = NULL;
223*4ceb1e51SAxel Dörfler 
22452a38012Sejakowatz 	return handler;
22552a38012Sejakowatz }
22652a38012Sejakowatz 
227*4ceb1e51SAxel Dörfler 
22852a38012Sejakowatz /*!	\brief Locks the BLooper targeted by the messenger, if the target is local.
22952a38012Sejakowatz 
23052a38012Sejakowatz 	This method is a shorthand for retrieving the targeted looper via
23152a38012Sejakowatz 	Target() and calling BLooper::Lock() on the looper afterwards.
23252a38012Sejakowatz 
23352a38012Sejakowatz 	\see BLooper::Lock() for details.
23452a38012Sejakowatz 
23552a38012Sejakowatz 	\return \c true, if the looper could be locked sucessfully, \c false, if
23652a38012Sejakowatz 			the messenger is not properly initialized, the target is remote,
23752a38012Sejakowatz 			or the targeted looper is invalid.
23852a38012Sejakowatz */
23952a38012Sejakowatz bool
24052a38012Sejakowatz BMessenger::LockTarget() const
24152a38012Sejakowatz {
24252a38012Sejakowatz 	BLooper *looper = NULL;
24352a38012Sejakowatz 	Target(&looper);
244*4ceb1e51SAxel Dörfler 	return looper && looper->Lock();
24552a38012Sejakowatz }
24652a38012Sejakowatz 
247*4ceb1e51SAxel Dörfler 
24852a38012Sejakowatz /*!	\brief Locks the BLooper targeted by the messenger, if the target is local.
24952a38012Sejakowatz 
25052a38012Sejakowatz 	This method is a shorthand for retrieving the targeted looper via
25152a38012Sejakowatz 	Target() and calling BLooper::LockWithTimeout() on the looper afterwards.
25252a38012Sejakowatz 
25352a38012Sejakowatz 	\see BLooper::LockWithTimeout() for details.
25452a38012Sejakowatz 
25552a38012Sejakowatz 	\return
25652a38012Sejakowatz 	- \c B_OK, if the looper could be locked sucessfully,
25752a38012Sejakowatz 	- \c B_BAD_VALUE, if the messenger is not properly initialized,
25852a38012Sejakowatz 	  the target is remote, or the targeted looper is invalid,
25952a38012Sejakowatz 	- other error codes returned by BLooper::LockWithTimeout().
26052a38012Sejakowatz */
26152a38012Sejakowatz status_t
26252a38012Sejakowatz BMessenger::LockTargetWithTimeout(bigtime_t timeout) const
26352a38012Sejakowatz {
26452a38012Sejakowatz 	BLooper *looper = NULL;
26552a38012Sejakowatz 	Target(&looper);
266*4ceb1e51SAxel Dörfler 	status_t error = looper ? B_OK : B_BAD_VALUE;
26752a38012Sejakowatz 	if (error == B_OK)
26852a38012Sejakowatz 		error = looper->LockWithTimeout(timeout);
269*4ceb1e51SAxel Dörfler 
27052a38012Sejakowatz 	return error;
27152a38012Sejakowatz }
27252a38012Sejakowatz 
27352a38012Sejakowatz 
274*4ceb1e51SAxel Dörfler //	#pragma mark - Message sending
27552a38012Sejakowatz 
27652a38012Sejakowatz // SendMessage
27752a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
27852a38012Sejakowatz 
2797e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
28052a38012Sejakowatz 
28152a38012Sejakowatz 	\param command The what field of the message to deliver.
28252a38012Sejakowatz 	\param replyTo The handler to which a reply to the message shall be sent.
28352a38012Sejakowatz 		   May be \c NULL.
28452a38012Sejakowatz 	\return
28552a38012Sejakowatz 	- \c B_OK: Everything went fine.
28652a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
28752a38012Sejakowatz 	  target doesn't exist anymore.
28852a38012Sejakowatz */
28952a38012Sejakowatz status_t
29052a38012Sejakowatz BMessenger::SendMessage(uint32 command, BHandler *replyTo) const
29152a38012Sejakowatz {
29252a38012Sejakowatz 	BMessage message(command);
29352a38012Sejakowatz 	return SendMessage(&message, replyTo);
29452a38012Sejakowatz }
29552a38012Sejakowatz 
29652a38012Sejakowatz // SendMessage
29752a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
29852a38012Sejakowatz 
29952a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
30052a38012Sejakowatz 	of \a message.
30152a38012Sejakowatz 
3027e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
30352a38012Sejakowatz 
30452a38012Sejakowatz 	\param message The message to be sent.
30552a38012Sejakowatz 	\param replyTo The handler to which a reply to the message shall be sent.
30652a38012Sejakowatz 		   May be \c NULL.
30752a38012Sejakowatz 	\param timeout A timeout for the delivery of the message.
30852a38012Sejakowatz 	\return
30952a38012Sejakowatz 	- \c B_OK: Everything went fine.
31052a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
31152a38012Sejakowatz 	  target doesn't exist anymore.
31252a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
31352a38012Sejakowatz 	  port was full when trying to deliver the message.
31452a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
31552a38012Sejakowatz 	  message.
31652a38012Sejakowatz */
31752a38012Sejakowatz status_t
31852a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BHandler *replyTo,
31952a38012Sejakowatz 						bigtime_t timeout) const
32052a38012Sejakowatz {
32152a38012Sejakowatz DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message->what));
32252a38012Sejakowatz 	status_t error = (message ? B_OK : B_BAD_VALUE);
32352a38012Sejakowatz 	if (error == B_OK) {
32452a38012Sejakowatz 		BMessenger replyMessenger(replyTo);
325717a24b7SIngo Weinhold 		error = SendMessage(message, replyMessenger, timeout);
32652a38012Sejakowatz 	}
32752a38012Sejakowatz DBG(OUT("BMessenger::SendMessage2() done: %lx\n", error));
32852a38012Sejakowatz 	return error;
32952a38012Sejakowatz }
33052a38012Sejakowatz 
33152a38012Sejakowatz // SendMessage
33252a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
33352a38012Sejakowatz 
33452a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
33552a38012Sejakowatz 	of \a message.
33652a38012Sejakowatz 
3377e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
33852a38012Sejakowatz 
33952a38012Sejakowatz 	\param message The message to be sent.
34052a38012Sejakowatz 	\param replyTo A messenger specifying the target for a reply to \a message.
34152a38012Sejakowatz 	\param timeout A timeout for the delivery of the message.
34252a38012Sejakowatz 	\return
34352a38012Sejakowatz 	- \c B_OK: Everything went fine.
34452a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
34552a38012Sejakowatz 	  target doesn't exist anymore.
34652a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
34752a38012Sejakowatz 	  port was full when trying to deliver the message.
34852a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
34952a38012Sejakowatz 	  message.
35052a38012Sejakowatz */
35152a38012Sejakowatz status_t
35252a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BMessenger replyTo,
35352a38012Sejakowatz 						bigtime_t timeout) const
35452a38012Sejakowatz {
3550d0f1600SJérôme Duval 	if (!message)
3560d0f1600SJérôme Duval 		return B_BAD_VALUE;
3570d0f1600SJérôme Duval 
358cf10934eSMichael Lotz #ifndef USING_MESSAGE4
359*4ceb1e51SAxel Dörfler 	return message->_send_(fPort, fHandlerToken, timeout, false, replyTo);
360cf10934eSMichael Lotz #else
361cf10934eSMichael Lotz 	return BMessage::Private(message).SendMessage(fPort, fHandlerToken,
362*4ceb1e51SAxel Dörfler 		timeout, false, replyTo);
363cf10934eSMichael Lotz #endif
36452a38012Sejakowatz }
36552a38012Sejakowatz 
36652a38012Sejakowatz // SendMessage
36752a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target and
36852a38012Sejakowatz 	waits for a reply.
36952a38012Sejakowatz 
37052a38012Sejakowatz 	The method does wait for a reply. The reply message is copied into
37152a38012Sejakowatz 	\a reply. If the target doesn't send a reply, the \c what field of
37252a38012Sejakowatz 	\a reply is set to \c B_NO_REPLY.
37352a38012Sejakowatz 
37452a38012Sejakowatz 	\param command The what field of the message to deliver.
37552a38012Sejakowatz 	\param reply A pointer to a pre-allocated BMessage into which the reply
37652a38012Sejakowatz 		   message will be copied.
37752a38012Sejakowatz 	\return
37852a38012Sejakowatz 	- \c B_OK: Everything went fine.
37952a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
38052a38012Sejakowatz 	  target doesn't exist anymore.
38152a38012Sejakowatz 	- \c B_NO_MORE_PORTS: All reply ports are in use.
38252a38012Sejakowatz */
38352a38012Sejakowatz status_t
38452a38012Sejakowatz BMessenger::SendMessage(uint32 command, BMessage *reply) const
38552a38012Sejakowatz {
38652a38012Sejakowatz 	BMessage message(command);
38752a38012Sejakowatz 	return SendMessage(&message, reply);
38852a38012Sejakowatz }
38952a38012Sejakowatz 
39052a38012Sejakowatz // SendMessage
39152a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target and
39252a38012Sejakowatz 	waits for a reply.
39352a38012Sejakowatz 
39452a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
39552a38012Sejakowatz 	of \a message.
39652a38012Sejakowatz 
39752a38012Sejakowatz 	The method does wait for a reply. The reply message is copied into
39852a38012Sejakowatz 	\a reply. If the target doesn't send a reply or if a reply timeout occurs,
39952a38012Sejakowatz 	the \c what field of \a reply is set to \c B_NO_REPLY.
40052a38012Sejakowatz 
40152a38012Sejakowatz 	\param message The message to be sent.
40252a38012Sejakowatz 	\param reply A pointer to a pre-allocated BMessage into which the reply
40352a38012Sejakowatz 		   message will be copied.
40452a38012Sejakowatz 	\param deliveryTimeout A timeout for the delivery of the message.
40552a38012Sejakowatz 	\param replyTimeout A timeout for waiting for the reply.
40652a38012Sejakowatz 	\return
40752a38012Sejakowatz 	- \c B_OK: Everything went fine.
40852a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
40952a38012Sejakowatz 	  target doesn't exist anymore.
41052a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
41152a38012Sejakowatz 	  port was full when trying to deliver the message.
41252a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
41352a38012Sejakowatz 	  message.
41452a38012Sejakowatz 	- \c B_NO_MORE_PORTS: All reply ports are in use.
41552a38012Sejakowatz */
41652a38012Sejakowatz status_t
41752a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BMessage *reply,
41852a38012Sejakowatz 	bigtime_t deliveryTimeout, bigtime_t replyTimeout) const
41952a38012Sejakowatz {
4208f1dc17dSIngo Weinhold 	status_t error = (message && reply ? B_OK : B_BAD_VALUE);
4218f1dc17dSIngo Weinhold 	if (error == B_OK) {
422cf10934eSMichael Lotz #ifndef USING_MESSAGE4
42352a38012Sejakowatz 		error = message->send_message(fPort, fTeam, fHandlerToken,
424*4ceb1e51SAxel Dörfler 			reply, deliveryTimeout, replyTimeout);
425cf10934eSMichael Lotz #else
426cf10934eSMichael Lotz 		error = BMessage::Private(message).SendMessage(fPort, fTeam,
427*4ceb1e51SAxel Dörfler 			fHandlerToken, reply, deliveryTimeout, replyTimeout);
428cf10934eSMichael Lotz #endif
4298f1dc17dSIngo Weinhold 		// Map this error for now:
4308f1dc17dSIngo Weinhold 		if (error == B_BAD_TEAM_ID)
4318f1dc17dSIngo Weinhold 			error = B_BAD_PORT_ID;
43252a38012Sejakowatz 	}
43352a38012Sejakowatz 	return error;
43452a38012Sejakowatz }
43552a38012Sejakowatz 
43652a38012Sejakowatz 
437*4ceb1e51SAxel Dörfler //	#pragma mark - Operators and misc
43852a38012Sejakowatz 
439*4ceb1e51SAxel Dörfler 
44052a38012Sejakowatz /*!	\brief Makes this BMessenger a copy of the supplied one.
44152a38012Sejakowatz 
44252a38012Sejakowatz 	\param from the messenger to be copied.
44352a38012Sejakowatz 	\return A reference to this object.
44452a38012Sejakowatz */
44552a38012Sejakowatz BMessenger &
44652a38012Sejakowatz BMessenger::operator=(const BMessenger &from)
44752a38012Sejakowatz {
44852a38012Sejakowatz 	if (this != &from) {
44952a38012Sejakowatz 		fPort = from.fPort;
45052a38012Sejakowatz 		fHandlerToken = from.fHandlerToken;
45152a38012Sejakowatz 		fTeam = from.fTeam;
45252a38012Sejakowatz 	}
4538f1dc17dSIngo Weinhold 	return *this;
45452a38012Sejakowatz }
45552a38012Sejakowatz 
456*4ceb1e51SAxel Dörfler 
45752a38012Sejakowatz /*!	\brief Returns whether this and the supplied messenger have the same
45852a38012Sejakowatz 	target.
45952a38012Sejakowatz 
46052a38012Sejakowatz 	\param other The other messenger.
46152a38012Sejakowatz 	\return \c true, if the messengers have the same target or if both aren't
46252a38012Sejakowatz 			properly initialzed, \c false otherwise.
46352a38012Sejakowatz */
46452a38012Sejakowatz bool
46552a38012Sejakowatz BMessenger::operator==(const BMessenger &other) const
46652a38012Sejakowatz {
4678f1dc17dSIngo Weinhold 	// Note: The fTeam fields are not compared.
468*4ceb1e51SAxel Dörfler 	return fPort == other.fPort
469*4ceb1e51SAxel Dörfler 		&& fHandlerToken == other.fHandlerToken;
47052a38012Sejakowatz }
47152a38012Sejakowatz 
472*4ceb1e51SAxel Dörfler 
47352a38012Sejakowatz /*!	\brief Returns whether the messenger's target looper does still exist.
47452a38012Sejakowatz 
47552a38012Sejakowatz 	It is not checked whether the target handler is also still existing.
47652a38012Sejakowatz 
47752a38012Sejakowatz 	\return \c true, if the messenger's target looper does still exist,
47852a38012Sejakowatz 			\c false otherwise.
47952a38012Sejakowatz */
48052a38012Sejakowatz bool
48152a38012Sejakowatz BMessenger::IsValid() const
48252a38012Sejakowatz {
48352a38012Sejakowatz 	port_info info;
484*4ceb1e51SAxel Dörfler 	return fPort >= 0 && get_port_info(fPort, &info) == B_OK;
48552a38012Sejakowatz }
48652a38012Sejakowatz 
487*4ceb1e51SAxel Dörfler 
48852a38012Sejakowatz /*!	\brief Returns the ID of the team the messenger's target lives in.
48952a38012Sejakowatz 
49052a38012Sejakowatz 	\return The team of the messenger's target.
49152a38012Sejakowatz */
49252a38012Sejakowatz team_id
49352a38012Sejakowatz BMessenger::Team() const
49452a38012Sejakowatz {
49552a38012Sejakowatz 	return fTeam;
49652a38012Sejakowatz }
49752a38012Sejakowatz 
49852a38012Sejakowatz 
499*4ceb1e51SAxel Dörfler //	#pragma mark - Private or reserved
50052a38012Sejakowatz 
501*4ceb1e51SAxel Dörfler 
5024afc60d3SIngo Weinhold /*!	\brief Sets the messenger's team, target looper port and handler token.
50352a38012Sejakowatz 
504*4ceb1e51SAxel Dörfler 	To target the preferred handler, use B_PREFERRED_TOKEN as token.
50552a38012Sejakowatz 
50652a38012Sejakowatz 	\param team The target's team.
50752a38012Sejakowatz 	\param port The target looper port.
50852a38012Sejakowatz 	\param token The target handler token.
50952a38012Sejakowatz */
5104afc60d3SIngo Weinhold void
511*4ceb1e51SAxel Dörfler BMessenger::_SetTo(team_id team, port_id port, int32 token)
51252a38012Sejakowatz {
51352a38012Sejakowatz 	fTeam = team;
51452a38012Sejakowatz 	fPort = port;
515*4ceb1e51SAxel Dörfler 	fHandlerToken = token;
51652a38012Sejakowatz }
51752a38012Sejakowatz 
518*4ceb1e51SAxel Dörfler 
51952a38012Sejakowatz /*!	\brief Initializes the BMessenger object's data given the signature and/or
52052a38012Sejakowatz 	team ID of a target.
52152a38012Sejakowatz 
52252a38012Sejakowatz 	When only a signature is given, and multiple instances of the application
52352a38012Sejakowatz 	are running it is undeterminate which one is chosen as the target. In case
52452a38012Sejakowatz 	only a team ID is passed, the target application is identified uniquely.
52552a38012Sejakowatz 	If both are supplied, the application identified by the team ID must have
52652a38012Sejakowatz 	a matching signature, otherwise the initilization fails.
52752a38012Sejakowatz 
52852a38012Sejakowatz 	\param signature The target application's signature. May be \c NULL.
52952a38012Sejakowatz 	\param team The target application's team ID. May be < 0.
53052a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
53152a38012Sejakowatz 		   the result of the initialization is written.
53252a38012Sejakowatz */
53352a38012Sejakowatz void
534*4ceb1e51SAxel Dörfler BMessenger::_InitData(const char* signature, team_id team, status_t* _result)
53552a38012Sejakowatz {
5363b044715SIngo Weinhold 	status_t error = B_OK;
5379e9f5a1aSIngo Weinhold 	// get an app_info
5389e9f5a1aSIngo Weinhold 	app_info info;
5393b044715SIngo Weinhold 	if (team < 0) {
5409e9f5a1aSIngo Weinhold 		// no team ID given
5413b044715SIngo Weinhold 		if (signature) {
5429e9f5a1aSIngo Weinhold 			error = be_roster->GetAppInfo(signature, &info);
5439e9f5a1aSIngo Weinhold 			team = info.team;
544672c1ea9SIngo Weinhold 			// B_ERROR means that no application with the given signature
545672c1ea9SIngo Weinhold 			// is running. But we are supposed to return B_BAD_VALUE.
546672c1ea9SIngo Weinhold 			if (error == B_ERROR)
5473b044715SIngo Weinhold 				error = B_BAD_VALUE;
548672c1ea9SIngo Weinhold 		} else
549672c1ea9SIngo Weinhold 			error = B_BAD_TYPE;
5509e9f5a1aSIngo Weinhold 	} else {
5519e9f5a1aSIngo Weinhold 		// a team ID is given
5523b044715SIngo Weinhold 		error = be_roster->GetRunningAppInfo(team, &info);
5539e9f5a1aSIngo Weinhold 		// Compare the returned signature with the supplied one.
5541771f7aeSAxel Dörfler 		if (error == B_OK && signature && strcasecmp(signature, info.signature))
555672c1ea9SIngo Weinhold 			error = B_MISMATCHED_VALUES;
5569e9f5a1aSIngo Weinhold 	}
5579e9f5a1aSIngo Weinhold 	// check whether the app flags say B_ARGV_ONLY
558672c1ea9SIngo Weinhold 	if (error == B_OK && (info.flags & B_ARGV_ONLY)) {
559c9f4f5e1SIngo Weinhold 		error = B_BAD_TYPE;
560672c1ea9SIngo Weinhold 		// Set the team ID nevertheless -- that's what Be's implementation
561672c1ea9SIngo Weinhold 		// does. Don't know, if that is a bug, but at least it doesn't harm.
562672c1ea9SIngo Weinhold 		fTeam = team;
563672c1ea9SIngo Weinhold 	}
5643b044715SIngo Weinhold 	// init our members
5653b044715SIngo Weinhold 	if (error == B_OK) {
5663b044715SIngo Weinhold 		fTeam = team;
5673b044715SIngo Weinhold 		fPort = info.port;
56894b98dffSIngo Weinhold 		fHandlerToken = B_PREFERRED_TOKEN;
56952a38012Sejakowatz 	}
57052a38012Sejakowatz 
571*4ceb1e51SAxel Dörfler 	// return the error
572*4ceb1e51SAxel Dörfler 	if (_result)
573*4ceb1e51SAxel Dörfler 		*_result = error;
574*4ceb1e51SAxel Dörfler }
575*4ceb1e51SAxel Dörfler 
576*4ceb1e51SAxel Dörfler 
57752a38012Sejakowatz /*!	\brief Returns whether the first one of two BMessengers is less than the
57852a38012Sejakowatz 	second one.
57952a38012Sejakowatz 
58052a38012Sejakowatz 	This method defines an order on BMessengers based on their member
5818f1dc17dSIngo Weinhold 	variables \c fPort, \c fHandlerToken and \c fPreferredTarget.
5828f1dc17dSIngo Weinhold 
58352a38012Sejakowatz 	\param a The first messenger.
58452a38012Sejakowatz 	\param b The second messenger.
58552a38012Sejakowatz 	\return \c true, if \a a is less than \a b, \c false otherwise.
58652a38012Sejakowatz */
58752a38012Sejakowatz bool
5884afc60d3SIngo Weinhold operator<(const BMessenger &_a, const BMessenger &_b)
58952a38012Sejakowatz {
5904afc60d3SIngo Weinhold 	BMessenger::Private a(const_cast<BMessenger&>(_a));
5914afc60d3SIngo Weinhold 	BMessenger::Private b(const_cast<BMessenger&>(_b));
5924afc60d3SIngo Weinhold 
5938f1dc17dSIngo Weinhold 	// significance:
5948f1dc17dSIngo Weinhold 	// 1. fPort
5958f1dc17dSIngo Weinhold 	// 2. fHandlerToken
5968f1dc17dSIngo Weinhold 	// 3. fPreferredTarget
5978f1dc17dSIngo Weinhold 	// fTeam is insignificant
5984afc60d3SIngo Weinhold 	return (a.Port() < b.Port()
5994afc60d3SIngo Weinhold 			|| a.Port() == b.Port()
6004afc60d3SIngo Weinhold 				&& (a.Token() < b.Token()
6014afc60d3SIngo Weinhold 					|| a.Token() == b.Token()
6024afc60d3SIngo Weinhold 						&& !a.IsPreferredTarget()
6034afc60d3SIngo Weinhold 						&& b.IsPreferredTarget()));
60452a38012Sejakowatz }
60552a38012Sejakowatz 
606*4ceb1e51SAxel Dörfler 
60752a38012Sejakowatz /*!	\brief Returns whether two BMessengers have not the same target.
60852a38012Sejakowatz 
60952a38012Sejakowatz 	\param a The first messenger.
61052a38012Sejakowatz 	\param b The second messenger.
61152a38012Sejakowatz 	\return \c false, if \a a and \a b have the same targets or are both not
61252a38012Sejakowatz 			properly initialized, \c true otherwise.
61352a38012Sejakowatz */
61452a38012Sejakowatz bool
61552a38012Sejakowatz operator!=(const BMessenger &a, const BMessenger &b)
61652a38012Sejakowatz {
61752a38012Sejakowatz 	return !(a == b);
61852a38012Sejakowatz }
61952a38012Sejakowatz 
620