xref: /haiku/src/kits/app/Messenger.cpp (revision 1771f7ae7951384f1c270fde2dfbc62304a819de)
152a38012Sejakowatz  //------------------------------------------------------------------------------
2*1771f7aeSAxel 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 
5452a38012Sejakowatz // Local Includes --------------------------------------------------------------
5552a38012Sejakowatz 
5652a38012Sejakowatz // Local Defines ---------------------------------------------------------------
5752a38012Sejakowatz 
5852a38012Sejakowatz // Globals ---------------------------------------------------------------------
5952a38012Sejakowatz 
6052a38012Sejakowatz using BPrivate::gDefaultTokens;
6137faaadeSIngo Weinhold using BPrivate::gLooperList;
6237faaadeSIngo Weinhold using BPrivate::BLooperList;
6337faaadeSIngo Weinhold using BPrivate::BObjectLocker;
6452a38012Sejakowatz 
6552a38012Sejakowatz enum {
6652a38012Sejakowatz 	NOT_IMPLEMENTED	= B_ERROR,
6752a38012Sejakowatz };
6852a38012Sejakowatz 
6952a38012Sejakowatz 
7052a38012Sejakowatz // constructor
7152a38012Sejakowatz /*!	\brief Creates an unitialized BMessenger.
7252a38012Sejakowatz */
7352a38012Sejakowatz BMessenger::BMessenger()
7452a38012Sejakowatz 		  : fPort(-1),
7594b98dffSIngo Weinhold 			fHandlerToken(B_NULL_TOKEN),
7652a38012Sejakowatz 			fTeam(-1),
7752a38012Sejakowatz 			fPreferredTarget(false)
7852a38012Sejakowatz {
7952a38012Sejakowatz }
8052a38012Sejakowatz 
8152a38012Sejakowatz // constructor
8252a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to target the already
8352a38012Sejakowatz 	running application identified by its signature and/or team ID.
8452a38012Sejakowatz 
8552a38012Sejakowatz 	When only a signature is given, and multiple instances of the application
8652a38012Sejakowatz 	are running it is undeterminate which one is chosen as the target. In case
8752a38012Sejakowatz 	only a team ID is passed, the target application is identified uniquely.
8852a38012Sejakowatz 	If both are supplied, the application identified by the team ID must have
8952a38012Sejakowatz 	a matching signature, otherwise the initilization fails.
9052a38012Sejakowatz 
9152a38012Sejakowatz 	\param signature The target application's signature. May be \c NULL.
9252a38012Sejakowatz 	\param team The target application's team ID. May be < 0.
9352a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
9452a38012Sejakowatz 		   the result of the initialization is written.
9552a38012Sejakowatz */
9652a38012Sejakowatz BMessenger::BMessenger(const char *signature, team_id team, status_t *result)
9752a38012Sejakowatz 		  : fPort(-1),
9894b98dffSIngo Weinhold 			fHandlerToken(B_NULL_TOKEN),
9952a38012Sejakowatz 			fTeam(-1),
10052a38012Sejakowatz 			fPreferredTarget(false)
10152a38012Sejakowatz {
10252a38012Sejakowatz 	InitData(signature, team, result);
10352a38012Sejakowatz }
10452a38012Sejakowatz 
10552a38012Sejakowatz // constructor
10652a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to target the local
10752a38012Sejakowatz 	BHandler and/or BLooper.
10852a38012Sejakowatz 
10952a38012Sejakowatz 	When a \c NULL handler is supplied, the preferred handler in the given
11052a38012Sejakowatz 	looper is targeted. If no looper is supplied the looper the given handler
11152a38012Sejakowatz 	belongs to is used -- that means in particular, that the handler must
11252a38012Sejakowatz 	already belong to a looper. If both are supplied the handler must actually
11352a38012Sejakowatz 	belong to looper.
11452a38012Sejakowatz 
11552a38012Sejakowatz 	\param handler The target handler. May be \c NULL.
11652a38012Sejakowatz 	\param looper The target looper. May be \c NULL.
11752a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
11852a38012Sejakowatz 		   the result of the initialization is written.
11952a38012Sejakowatz */
12052a38012Sejakowatz BMessenger::BMessenger(const BHandler *handler, const BLooper *looper,
12152a38012Sejakowatz 					   status_t *result)
12252a38012Sejakowatz 		  : fPort(-1),
12394b98dffSIngo Weinhold 			fHandlerToken(B_NULL_TOKEN),
12452a38012Sejakowatz 			fTeam(-1),
12552a38012Sejakowatz 			fPreferredTarget(false)
12652a38012Sejakowatz {
12752a38012Sejakowatz 	status_t error = (handler || looper ? B_OK : B_BAD_VALUE);
12852a38012Sejakowatz 	if (error == B_OK) {
12952a38012Sejakowatz 		if (handler) {
13052a38012Sejakowatz 			// BHandler is given, check/retrieve the looper.
13152a38012Sejakowatz 			if (looper) {
13252a38012Sejakowatz 				if (handler->Looper() != looper)
13352a38012Sejakowatz 					error = B_MISMATCHED_VALUES;
13452a38012Sejakowatz 			} else {
13552a38012Sejakowatz 				looper = handler->Looper();
13652a38012Sejakowatz 				if (looper == NULL)
13752a38012Sejakowatz 					error = B_MISMATCHED_VALUES;
13852a38012Sejakowatz 			}
13937faaadeSIngo Weinhold 		}
14052a38012Sejakowatz 		// set port, token,...
14152a38012Sejakowatz 		if (error == B_OK) {
14237faaadeSIngo Weinhold 			BObjectLocker<BLooperList> locker(gLooperList);
14337faaadeSIngo Weinhold 			if (locker.IsLocked() && gLooperList.IsLooperValid(looper)) {
14452a38012Sejakowatz 				fPort = looper->fMsgPort;
14594b98dffSIngo Weinhold 				fHandlerToken = (handler
14694b98dffSIngo Weinhold 					? _get_object_token_(handler) : B_PREFERRED_TOKEN);
14737faaadeSIngo Weinhold 				fPreferredTarget = !handler;
14837faaadeSIngo Weinhold 				fTeam = looper->Team();
14937faaadeSIngo Weinhold 			} else
15037faaadeSIngo Weinhold 				error = B_BAD_VALUE;
15152a38012Sejakowatz 		}
15252a38012Sejakowatz 	}
15352a38012Sejakowatz 	if (result)
15452a38012Sejakowatz 		*result = error;
15552a38012Sejakowatz }
15652a38012Sejakowatz 
15752a38012Sejakowatz // copy constructor
15852a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to have the same target
15952a38012Sejakowatz 	as the supplied messemger.
16052a38012Sejakowatz 
16152a38012Sejakowatz 	\param from The messenger to be copied.
16252a38012Sejakowatz */
16352a38012Sejakowatz BMessenger::BMessenger(const BMessenger &from)
16452a38012Sejakowatz 		  : fPort(from.fPort),
16552a38012Sejakowatz 			fHandlerToken(from.fHandlerToken),
16652a38012Sejakowatz 			fTeam(from.fTeam),
16752a38012Sejakowatz 			fPreferredTarget(from.fPreferredTarget)
16852a38012Sejakowatz {
16952a38012Sejakowatz }
17052a38012Sejakowatz 
17152a38012Sejakowatz // destructor
17252a38012Sejakowatz /*!	\brief Frees all resources associated with this object.
17352a38012Sejakowatz */
17452a38012Sejakowatz BMessenger::~BMessenger()
17552a38012Sejakowatz {
17652a38012Sejakowatz }
17752a38012Sejakowatz 
17852a38012Sejakowatz 
17952a38012Sejakowatz // Target
18052a38012Sejakowatz 
18152a38012Sejakowatz // IsTargetLocal
18252a38012Sejakowatz /*!	\brief Returns whether or not the messenger's target lives within the team
18352a38012Sejakowatz 	of the caller.
18452a38012Sejakowatz 
18552a38012Sejakowatz 	\return \c true, if the object is properly initialized and its target
18652a38012Sejakowatz 			lives within the caller's team, \c false otherwise.
18752a38012Sejakowatz */
18852a38012Sejakowatz bool
18952a38012Sejakowatz BMessenger::IsTargetLocal() const
19052a38012Sejakowatz {
19152a38012Sejakowatz 	thread_info info;
19252a38012Sejakowatz 	return (get_thread_info(find_thread(NULL), &info) == B_OK
19352a38012Sejakowatz 			&& fTeam == info.team);
19452a38012Sejakowatz }
19552a38012Sejakowatz 
19652a38012Sejakowatz // Target
19752a38012Sejakowatz /*!	\brief Returns the handler and looper targeted by the messenger, if the
19852a38012Sejakowatz 	target is local.
19952a38012Sejakowatz 
20052a38012Sejakowatz 	The handler is returned directly, the looper by reference. If both are
20152a38012Sejakowatz 	\c NULL, the object is either not properly initialized, the target
20252a38012Sejakowatz 	objects have been deleted or the target is remote. If only the returned
20352a38012Sejakowatz 	handler is \c NULL, either the looper's preferred handler is targeted or
20452a38012Sejakowatz 	the handler has been deleted.
20552a38012Sejakowatz 
20652a38012Sejakowatz 	\param looper A pointer to a pre-allocated BLooper pointer into which
20752a38012Sejakowatz 		   the pointer to the targeted looper is written.
20852a38012Sejakowatz 	\return The BHandler targeted by the messenger.
20952a38012Sejakowatz */
21052a38012Sejakowatz BHandler *
21152a38012Sejakowatz BMessenger::Target(BLooper **looper) const
21252a38012Sejakowatz {
21352a38012Sejakowatz 	BHandler *handler = NULL;
21452a38012Sejakowatz 	if (IsTargetLocal()) {
21552a38012Sejakowatz 		if (!fPreferredTarget) {
21652a38012Sejakowatz 			gDefaultTokens.GetToken(fHandlerToken, B_HANDLER_TOKEN,
21752a38012Sejakowatz 									(void**)&handler);
21852a38012Sejakowatz 		}
219e1f41e5dSIngo Weinhold 		if (looper)
220e1f41e5dSIngo Weinhold 			*looper = BPrivate::gLooperList.LooperForPort(fPort);
22152a38012Sejakowatz 	} else if (looper)
22252a38012Sejakowatz 		*looper = NULL;
22352a38012Sejakowatz 	return handler;
22452a38012Sejakowatz }
22552a38012Sejakowatz 
22652a38012Sejakowatz // LockTarget
22752a38012Sejakowatz /*!	\brief Locks the BLooper targeted by the messenger, if the target is local.
22852a38012Sejakowatz 
22952a38012Sejakowatz 	This method is a shorthand for retrieving the targeted looper via
23052a38012Sejakowatz 	Target() and calling BLooper::Lock() on the looper afterwards.
23152a38012Sejakowatz 
23252a38012Sejakowatz 	\see BLooper::Lock() for details.
23352a38012Sejakowatz 
23452a38012Sejakowatz 	\return \c true, if the looper could be locked sucessfully, \c false, if
23552a38012Sejakowatz 			the messenger is not properly initialized, the target is remote,
23652a38012Sejakowatz 			or the targeted looper is invalid.
23752a38012Sejakowatz */
23852a38012Sejakowatz bool
23952a38012Sejakowatz BMessenger::LockTarget() const
24052a38012Sejakowatz {
24152a38012Sejakowatz 	BLooper *looper = NULL;
24252a38012Sejakowatz 	Target(&looper);
24352a38012Sejakowatz 	return (looper && looper->Lock());
24452a38012Sejakowatz }
24552a38012Sejakowatz 
24652a38012Sejakowatz // LockTargetWithTimeout
24752a38012Sejakowatz /*!	\brief Locks the BLooper targeted by the messenger, if the target is local.
24852a38012Sejakowatz 
24952a38012Sejakowatz 	This method is a shorthand for retrieving the targeted looper via
25052a38012Sejakowatz 	Target() and calling BLooper::LockWithTimeout() on the looper afterwards.
25152a38012Sejakowatz 
25252a38012Sejakowatz 	\see BLooper::LockWithTimeout() for details.
25352a38012Sejakowatz 
25452a38012Sejakowatz 	\return
25552a38012Sejakowatz 	- \c B_OK, if the looper could be locked sucessfully,
25652a38012Sejakowatz 	- \c B_BAD_VALUE, if the messenger is not properly initialized,
25752a38012Sejakowatz 	  the target is remote, or the targeted looper is invalid,
25852a38012Sejakowatz 	- other error codes returned by BLooper::LockWithTimeout().
25952a38012Sejakowatz */
26052a38012Sejakowatz status_t
26152a38012Sejakowatz BMessenger::LockTargetWithTimeout(bigtime_t timeout) const
26252a38012Sejakowatz {
26352a38012Sejakowatz 	BLooper *looper = NULL;
26452a38012Sejakowatz 	Target(&looper);
26552a38012Sejakowatz 	status_t error = (looper ? B_OK : B_BAD_VALUE);
26652a38012Sejakowatz 	if (error == B_OK)
26752a38012Sejakowatz 		error = looper->LockWithTimeout(timeout);
26852a38012Sejakowatz 	return error;
26952a38012Sejakowatz }
27052a38012Sejakowatz 
27152a38012Sejakowatz 
27252a38012Sejakowatz // Message sending
27352a38012Sejakowatz 
27452a38012Sejakowatz // SendMessage
27552a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
27652a38012Sejakowatz 
2777e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
27852a38012Sejakowatz 
27952a38012Sejakowatz 	\param command The what field of the message to deliver.
28052a38012Sejakowatz 	\param replyTo The handler to which a reply to the message shall be sent.
28152a38012Sejakowatz 		   May be \c NULL.
28252a38012Sejakowatz 	\return
28352a38012Sejakowatz 	- \c B_OK: Everything went fine.
28452a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
28552a38012Sejakowatz 	  target doesn't exist anymore.
28652a38012Sejakowatz */
28752a38012Sejakowatz status_t
28852a38012Sejakowatz BMessenger::SendMessage(uint32 command, BHandler *replyTo) const
28952a38012Sejakowatz {
29052a38012Sejakowatz 	BMessage message(command);
29152a38012Sejakowatz 	return SendMessage(&message, replyTo);
29252a38012Sejakowatz }
29352a38012Sejakowatz 
29452a38012Sejakowatz // SendMessage
29552a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
29652a38012Sejakowatz 
29752a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
29852a38012Sejakowatz 	of \a message.
29952a38012Sejakowatz 
3007e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
30152a38012Sejakowatz 
30252a38012Sejakowatz 	\param message The message to be sent.
30352a38012Sejakowatz 	\param replyTo The handler to which a reply to the message shall be sent.
30452a38012Sejakowatz 		   May be \c NULL.
30552a38012Sejakowatz 	\param timeout A timeout for the delivery of the message.
30652a38012Sejakowatz 	\return
30752a38012Sejakowatz 	- \c B_OK: Everything went fine.
30852a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
30952a38012Sejakowatz 	  target doesn't exist anymore.
31052a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
31152a38012Sejakowatz 	  port was full when trying to deliver the message.
31252a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
31352a38012Sejakowatz 	  message.
31452a38012Sejakowatz */
31552a38012Sejakowatz status_t
31652a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BHandler *replyTo,
31752a38012Sejakowatz 						bigtime_t timeout) const
31852a38012Sejakowatz {
31952a38012Sejakowatz DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message->what));
32052a38012Sejakowatz 	status_t error = (message ? B_OK : B_BAD_VALUE);
32152a38012Sejakowatz 	if (error == B_OK) {
32252a38012Sejakowatz 		BMessenger replyMessenger(replyTo);
323717a24b7SIngo Weinhold 		error = SendMessage(message, replyMessenger, timeout);
32452a38012Sejakowatz 	}
32552a38012Sejakowatz DBG(OUT("BMessenger::SendMessage2() done: %lx\n", error));
32652a38012Sejakowatz 	return error;
32752a38012Sejakowatz }
32852a38012Sejakowatz 
32952a38012Sejakowatz // SendMessage
33052a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
33152a38012Sejakowatz 
33252a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
33352a38012Sejakowatz 	of \a message.
33452a38012Sejakowatz 
3357e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
33652a38012Sejakowatz 
33752a38012Sejakowatz 	\param message The message to be sent.
33852a38012Sejakowatz 	\param replyTo A messenger specifying the target for a reply to \a message.
33952a38012Sejakowatz 	\param timeout A timeout for the delivery of the message.
34052a38012Sejakowatz 	\return
34152a38012Sejakowatz 	- \c B_OK: Everything went fine.
34252a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
34352a38012Sejakowatz 	  target doesn't exist anymore.
34452a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
34552a38012Sejakowatz 	  port was full when trying to deliver the message.
34652a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
34752a38012Sejakowatz 	  message.
34852a38012Sejakowatz */
34952a38012Sejakowatz status_t
35052a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BMessenger replyTo,
35152a38012Sejakowatz 						bigtime_t timeout) const
35252a38012Sejakowatz {
3530d0f1600SJérôme Duval 	if (!message)
3540d0f1600SJérôme Duval 		return B_BAD_VALUE;
3550d0f1600SJérôme Duval 
3560d0f1600SJérôme Duval 	return message->_send_(fPort, fHandlerToken, fPreferredTarget,
357717a24b7SIngo Weinhold 		timeout, false, replyTo);
35852a38012Sejakowatz }
35952a38012Sejakowatz 
36052a38012Sejakowatz // SendMessage
36152a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target and
36252a38012Sejakowatz 	waits for a reply.
36352a38012Sejakowatz 
36452a38012Sejakowatz 	The method does wait for a reply. The reply message is copied into
36552a38012Sejakowatz 	\a reply. If the target doesn't send a reply, the \c what field of
36652a38012Sejakowatz 	\a reply is set to \c B_NO_REPLY.
36752a38012Sejakowatz 
36852a38012Sejakowatz 	\param command The what field of the message to deliver.
36952a38012Sejakowatz 	\param reply A pointer to a pre-allocated BMessage into which the reply
37052a38012Sejakowatz 		   message will be copied.
37152a38012Sejakowatz 	\return
37252a38012Sejakowatz 	- \c B_OK: Everything went fine.
37352a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
37452a38012Sejakowatz 	  target doesn't exist anymore.
37552a38012Sejakowatz 	- \c B_NO_MORE_PORTS: All reply ports are in use.
37652a38012Sejakowatz */
37752a38012Sejakowatz status_t
37852a38012Sejakowatz BMessenger::SendMessage(uint32 command, BMessage *reply) const
37952a38012Sejakowatz {
38052a38012Sejakowatz 	BMessage message(command);
38152a38012Sejakowatz 	return SendMessage(&message, reply);
38252a38012Sejakowatz }
38352a38012Sejakowatz 
38452a38012Sejakowatz // SendMessage
38552a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target and
38652a38012Sejakowatz 	waits for a reply.
38752a38012Sejakowatz 
38852a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
38952a38012Sejakowatz 	of \a message.
39052a38012Sejakowatz 
39152a38012Sejakowatz 	The method does wait for a reply. The reply message is copied into
39252a38012Sejakowatz 	\a reply. If the target doesn't send a reply or if a reply timeout occurs,
39352a38012Sejakowatz 	the \c what field of \a reply is set to \c B_NO_REPLY.
39452a38012Sejakowatz 
39552a38012Sejakowatz 	\param message The message to be sent.
39652a38012Sejakowatz 	\param reply A pointer to a pre-allocated BMessage into which the reply
39752a38012Sejakowatz 		   message will be copied.
39852a38012Sejakowatz 	\param deliveryTimeout A timeout for the delivery of the message.
39952a38012Sejakowatz 	\param replyTimeout A timeout for waiting for the reply.
40052a38012Sejakowatz 	\return
40152a38012Sejakowatz 	- \c B_OK: Everything went fine.
40252a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
40352a38012Sejakowatz 	  target doesn't exist anymore.
40452a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
40552a38012Sejakowatz 	  port was full when trying to deliver the message.
40652a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
40752a38012Sejakowatz 	  message.
40852a38012Sejakowatz 	- \c B_NO_MORE_PORTS: All reply ports are in use.
40952a38012Sejakowatz */
41052a38012Sejakowatz status_t
41152a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BMessage *reply,
41252a38012Sejakowatz 						bigtime_t deliveryTimeout, bigtime_t replyTimeout) const
41352a38012Sejakowatz {
4148f1dc17dSIngo Weinhold 	status_t error = (message && reply ? B_OK : B_BAD_VALUE);
4158f1dc17dSIngo Weinhold 	if (error == B_OK) {
41652a38012Sejakowatz 		error = message->send_message(fPort, fTeam, fHandlerToken,
41752a38012Sejakowatz 									  fPreferredTarget, reply, deliveryTimeout,
41852a38012Sejakowatz 									  replyTimeout);
4198f1dc17dSIngo Weinhold 		// Map this error for now:
4208f1dc17dSIngo Weinhold 		if (error == B_BAD_TEAM_ID)
4218f1dc17dSIngo Weinhold 			error = B_BAD_PORT_ID;
42252a38012Sejakowatz 	}
42352a38012Sejakowatz 	return error;
42452a38012Sejakowatz }
42552a38012Sejakowatz 
42652a38012Sejakowatz 
42752a38012Sejakowatz // Operators and misc
42852a38012Sejakowatz 
42952a38012Sejakowatz // =
43052a38012Sejakowatz /*!	\brief Makes this BMessenger a copy of the supplied one.
43152a38012Sejakowatz 
43252a38012Sejakowatz 	\param from the messenger to be copied.
43352a38012Sejakowatz 	\return A reference to this object.
43452a38012Sejakowatz */
43552a38012Sejakowatz BMessenger &
43652a38012Sejakowatz BMessenger::operator=(const BMessenger &from)
43752a38012Sejakowatz {
43852a38012Sejakowatz 	if (this != &from) {
43952a38012Sejakowatz 		fPort = from.fPort;
44052a38012Sejakowatz 		fHandlerToken = from.fHandlerToken;
44152a38012Sejakowatz 		fTeam = from.fTeam;
44252a38012Sejakowatz 		fPreferredTarget = from.fPreferredTarget;
44352a38012Sejakowatz 	}
4448f1dc17dSIngo Weinhold 	return *this;
44552a38012Sejakowatz }
44652a38012Sejakowatz 
44752a38012Sejakowatz // ==
44852a38012Sejakowatz /*!	\brief Returns whether this and the supplied messenger have the same
44952a38012Sejakowatz 	target.
45052a38012Sejakowatz 
45152a38012Sejakowatz 	\param other The other messenger.
45252a38012Sejakowatz 	\return \c true, if the messengers have the same target or if both aren't
45352a38012Sejakowatz 			properly initialzed, \c false otherwise.
45452a38012Sejakowatz */
45552a38012Sejakowatz bool
45652a38012Sejakowatz BMessenger::operator==(const BMessenger &other) const
45752a38012Sejakowatz {
4588f1dc17dSIngo Weinhold 	// Note: The fTeam fields are not compared.
45952a38012Sejakowatz 	return (fPort == other.fPort
46052a38012Sejakowatz 			&& fHandlerToken == other.fHandlerToken
46152a38012Sejakowatz 			&& fPreferredTarget == other.fPreferredTarget);
46252a38012Sejakowatz }
46352a38012Sejakowatz 
46452a38012Sejakowatz // IsValid
46552a38012Sejakowatz /*!	\brief Returns whether the messenger's target looper does still exist.
46652a38012Sejakowatz 
46752a38012Sejakowatz 	It is not checked whether the target handler is also still existing.
46852a38012Sejakowatz 
46952a38012Sejakowatz 	\return \c true, if the messenger's target looper does still exist,
47052a38012Sejakowatz 			\c false otherwise.
47152a38012Sejakowatz */
47252a38012Sejakowatz bool
47352a38012Sejakowatz BMessenger::IsValid() const
47452a38012Sejakowatz {
47552a38012Sejakowatz 	port_info info;
47652a38012Sejakowatz 	return (fPort >= 0 && get_port_info(fPort, &info) == B_OK);
47752a38012Sejakowatz }
47852a38012Sejakowatz 
47952a38012Sejakowatz // Team
48052a38012Sejakowatz /*!	\brief Returns the ID of the team the messenger's target lives in.
48152a38012Sejakowatz 
48252a38012Sejakowatz 	\return The team of the messenger's target.
48352a38012Sejakowatz */
48452a38012Sejakowatz team_id
48552a38012Sejakowatz BMessenger::Team() const
48652a38012Sejakowatz {
48752a38012Sejakowatz 	return fTeam;
48852a38012Sejakowatz }
48952a38012Sejakowatz 
49052a38012Sejakowatz 
49152a38012Sejakowatz //----- Private or reserved -----------------------------------------
49252a38012Sejakowatz 
4934afc60d3SIngo Weinhold // SetTo
4944afc60d3SIngo Weinhold /*!	\brief Sets the messenger's team, target looper port and handler token.
49552a38012Sejakowatz 
49652a38012Sejakowatz 	If \a preferred is \c true, \a token is ignored.
49752a38012Sejakowatz 
49852a38012Sejakowatz 	\param team The target's team.
49952a38012Sejakowatz 	\param port The target looper port.
50052a38012Sejakowatz 	\param token The target handler token.
50152a38012Sejakowatz 	\param preferred \c true to rather use the looper's preferred handler
50252a38012Sejakowatz 		   instead of the one specified by \a token.
50352a38012Sejakowatz */
5044afc60d3SIngo Weinhold void
5054afc60d3SIngo Weinhold BMessenger::SetTo(team_id team, port_id port, int32 token, bool preferred)
50652a38012Sejakowatz {
50752a38012Sejakowatz 	fTeam = team;
50852a38012Sejakowatz 	fPort = port;
50994b98dffSIngo Weinhold 	fHandlerToken = (preferred ? B_PREFERRED_TOKEN : token);
51052a38012Sejakowatz 	fPreferredTarget = preferred;
51152a38012Sejakowatz }
51252a38012Sejakowatz 
51352a38012Sejakowatz // InitData
51452a38012Sejakowatz /*!	\brief Initializes the BMessenger object's data given the signature and/or
51552a38012Sejakowatz 	team ID of a target.
51652a38012Sejakowatz 
51752a38012Sejakowatz 	When only a signature is given, and multiple instances of the application
51852a38012Sejakowatz 	are running it is undeterminate which one is chosen as the target. In case
51952a38012Sejakowatz 	only a team ID is passed, the target application is identified uniquely.
52052a38012Sejakowatz 	If both are supplied, the application identified by the team ID must have
52152a38012Sejakowatz 	a matching signature, otherwise the initilization fails.
52252a38012Sejakowatz 
52352a38012Sejakowatz 	\param signature The target application's signature. May be \c NULL.
52452a38012Sejakowatz 	\param team The target application's team ID. May be < 0.
52552a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
52652a38012Sejakowatz 		   the result of the initialization is written.
52752a38012Sejakowatz */
52852a38012Sejakowatz void
52952a38012Sejakowatz BMessenger::InitData(const char *signature, team_id team, status_t *result)
53052a38012Sejakowatz {
5313b044715SIngo Weinhold 	status_t error = B_OK;
5329e9f5a1aSIngo Weinhold 	// get an app_info
5339e9f5a1aSIngo Weinhold 	app_info info;
5343b044715SIngo Weinhold 	if (team < 0) {
5359e9f5a1aSIngo Weinhold 		// no team ID given
5363b044715SIngo Weinhold 		if (signature) {
5379e9f5a1aSIngo Weinhold 			error = be_roster->GetAppInfo(signature, &info);
5389e9f5a1aSIngo Weinhold 			team = info.team;
539672c1ea9SIngo Weinhold 			// B_ERROR means that no application with the given signature
540672c1ea9SIngo Weinhold 			// is running. But we are supposed to return B_BAD_VALUE.
541672c1ea9SIngo Weinhold 			if (error == B_ERROR)
5423b044715SIngo Weinhold 				error = B_BAD_VALUE;
543672c1ea9SIngo Weinhold 		} else
544672c1ea9SIngo Weinhold 			error = B_BAD_TYPE;
5459e9f5a1aSIngo Weinhold 	} else {
5469e9f5a1aSIngo Weinhold 		// a team ID is given
5473b044715SIngo Weinhold 		error = be_roster->GetRunningAppInfo(team, &info);
5489e9f5a1aSIngo Weinhold 		// Compare the returned signature with the supplied one.
549*1771f7aeSAxel Dörfler 		if (error == B_OK && signature && strcasecmp(signature, info.signature))
550672c1ea9SIngo Weinhold 			error = B_MISMATCHED_VALUES;
5519e9f5a1aSIngo Weinhold 	}
5529e9f5a1aSIngo Weinhold 	// check whether the app flags say B_ARGV_ONLY
553672c1ea9SIngo Weinhold 	if (error == B_OK && (info.flags & B_ARGV_ONLY)) {
554c9f4f5e1SIngo Weinhold 		error = B_BAD_TYPE;
555672c1ea9SIngo Weinhold 		// Set the team ID nevertheless -- that's what Be's implementation
556672c1ea9SIngo Weinhold 		// does. Don't know, if that is a bug, but at least it doesn't harm.
557672c1ea9SIngo Weinhold 		fTeam = team;
558672c1ea9SIngo Weinhold 	}
5593b044715SIngo Weinhold 	// init our members
5603b044715SIngo Weinhold 	if (error == B_OK) {
5613b044715SIngo Weinhold 		fTeam = team;
5623b044715SIngo Weinhold 		fPort = info.port;
56394b98dffSIngo Weinhold 		fHandlerToken = B_PREFERRED_TOKEN;
5643b044715SIngo Weinhold 		fPreferredTarget = true;
5653b044715SIngo Weinhold 	}
5663b044715SIngo Weinhold 	// return the error
56752a38012Sejakowatz 	if (result)
5683b044715SIngo Weinhold 		*result = error;
56952a38012Sejakowatz }
57052a38012Sejakowatz 
57152a38012Sejakowatz // <
57252a38012Sejakowatz /*!	\brief Returns whether the first one of two BMessengers is less than the
57352a38012Sejakowatz 	second one.
57452a38012Sejakowatz 
57552a38012Sejakowatz 	This method defines an order on BMessengers based on their member
5768f1dc17dSIngo Weinhold 	variables \c fPort, \c fHandlerToken and \c fPreferredTarget.
5778f1dc17dSIngo Weinhold 
57852a38012Sejakowatz 	\param a The first messenger.
57952a38012Sejakowatz 	\param b The second messenger.
58052a38012Sejakowatz 	\return \c true, if \a a is less than \a b, \c false otherwise.
58152a38012Sejakowatz */
58252a38012Sejakowatz bool
5834afc60d3SIngo Weinhold operator<(const BMessenger &_a, const BMessenger &_b)
58452a38012Sejakowatz {
5854afc60d3SIngo Weinhold 	BMessenger::Private a(const_cast<BMessenger&>(_a));
5864afc60d3SIngo Weinhold 	BMessenger::Private b(const_cast<BMessenger&>(_b));
5874afc60d3SIngo Weinhold 
5884afc60d3SIngo Weinhold 
5898f1dc17dSIngo Weinhold 	// significance:
5908f1dc17dSIngo Weinhold 	// 1. fPort
5918f1dc17dSIngo Weinhold 	// 2. fHandlerToken
5928f1dc17dSIngo Weinhold 	// 3. fPreferredTarget
5938f1dc17dSIngo Weinhold 	// fTeam is insignificant
5944afc60d3SIngo Weinhold 	return (a.Port() < b.Port()
5954afc60d3SIngo Weinhold 			|| a.Port() == b.Port()
5964afc60d3SIngo Weinhold 				&& (a.Token() < b.Token()
5974afc60d3SIngo Weinhold 					|| a.Token() == b.Token()
5984afc60d3SIngo Weinhold 						&& !a.IsPreferredTarget()
5994afc60d3SIngo Weinhold 						&& b.IsPreferredTarget()));
60052a38012Sejakowatz }
60152a38012Sejakowatz 
60252a38012Sejakowatz // !=
60352a38012Sejakowatz /*!	\brief Returns whether two BMessengers have not the same target.
60452a38012Sejakowatz 
60552a38012Sejakowatz 	\param a The first messenger.
60652a38012Sejakowatz 	\param b The second messenger.
60752a38012Sejakowatz 	\return \c false, if \a a and \a b have the same targets or are both not
60852a38012Sejakowatz 			properly initialized, \c true otherwise.
60952a38012Sejakowatz */
61052a38012Sejakowatz bool
61152a38012Sejakowatz operator!=(const BMessenger &a, const BMessenger &b)
61252a38012Sejakowatz {
61352a38012Sejakowatz 	return !(a == b);
61452a38012Sejakowatz }
61552a38012Sejakowatz 
616