xref: /haiku/src/kits/app/Messenger.cpp (revision 9e9f5a1ad34c5bbefe475da7114a7dc53cb26bf3)
152a38012Sejakowatz  //------------------------------------------------------------------------------
252a38012Sejakowatz //	Copyright (c) 2001-2002, OpenBeOS
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>
35*9e9f5a1aSIngo 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>
4652a38012Sejakowatz 
4752a38012Sejakowatz // Project Includes ------------------------------------------------------------
4852a38012Sejakowatz #include "TokenSpace.h"
4952a38012Sejakowatz 
5052a38012Sejakowatz // Local Includes --------------------------------------------------------------
5152a38012Sejakowatz 
5252a38012Sejakowatz // Local Defines ---------------------------------------------------------------
5352a38012Sejakowatz 
5452a38012Sejakowatz // Globals ---------------------------------------------------------------------
5552a38012Sejakowatz 
5652a38012Sejakowatz using BPrivate::gDefaultTokens;
5752a38012Sejakowatz 
5852a38012Sejakowatz enum {
5952a38012Sejakowatz 	NOT_IMPLEMENTED	= B_ERROR,
6052a38012Sejakowatz };
6152a38012Sejakowatz 
6252a38012Sejakowatz // _get_object_token_
6352a38012Sejakowatz /*!	Return the token of a BHandler.
6452a38012Sejakowatz 
6552a38012Sejakowatz 	\param handler The BHandler.
6652a38012Sejakowatz 	\return the token.
6752a38012Sejakowatz 
6852a38012Sejakowatz 	\todo Think about a better place for this function.
6952a38012Sejakowatz */
7052a38012Sejakowatz inline
7152a38012Sejakowatz int32
7252a38012Sejakowatz _get_object_token_(const BHandler* handler)
7352a38012Sejakowatz {
7452a38012Sejakowatz 	return handler->fToken;
7552a38012Sejakowatz }
7652a38012Sejakowatz 
7752a38012Sejakowatz // _set_message_target_
7852a38012Sejakowatz /*!	\brief Sets the target of a message.
7952a38012Sejakowatz 
8052a38012Sejakowatz 	\param message The message.
8152a38012Sejakowatz 	\param token The target handler token.
8252a38012Sejakowatz 	\param preferred Indicates whether to use the looper's preferred handler.
8352a38012Sejakowatz */
8452a38012Sejakowatz inline
8552a38012Sejakowatz void
8652a38012Sejakowatz _set_message_target_(BMessage *message, int32 token, bool preferred)
8752a38012Sejakowatz {
8852a38012Sejakowatz 	message->fTarget = token;
8952a38012Sejakowatz 	message->fPreferred = preferred;
9052a38012Sejakowatz }
9152a38012Sejakowatz 
9252a38012Sejakowatz // _set_message_reply_
9352a38012Sejakowatz /*!	\brief Sets a message's reply target.
9452a38012Sejakowatz 
9552a38012Sejakowatz 	\param message The message.
9652a38012Sejakowatz 	\param messenger The reply messenger.
9752a38012Sejakowatz */
9852a38012Sejakowatz inline
9952a38012Sejakowatz void
10052a38012Sejakowatz _set_message_reply_(BMessage *message, BMessenger messenger)
10152a38012Sejakowatz {
10252a38012Sejakowatz 	message->fReplyTo.port = messenger.fPort;
10352a38012Sejakowatz 	message->fReplyTo.target = messenger.fHandlerToken;
10452a38012Sejakowatz 	message->fReplyTo.team = messenger.fTeam;
10552a38012Sejakowatz 	message->fReplyTo.preferred = messenger.fPreferredTarget;
10652a38012Sejakowatz }
10752a38012Sejakowatz 
10852a38012Sejakowatz // constructor
10952a38012Sejakowatz /*!	\brief Creates an unitialized BMessenger.
11052a38012Sejakowatz */
11152a38012Sejakowatz BMessenger::BMessenger()
11252a38012Sejakowatz 		  : fPort(-1),
11352a38012Sejakowatz 			fHandlerToken(-1),
11452a38012Sejakowatz 			fTeam(-1),
11552a38012Sejakowatz 			fPreferredTarget(false)
11652a38012Sejakowatz {
11752a38012Sejakowatz }
11852a38012Sejakowatz 
11952a38012Sejakowatz // constructor
12052a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to target the already
12152a38012Sejakowatz 	running application identified by its signature and/or team ID.
12252a38012Sejakowatz 
12352a38012Sejakowatz 	When only a signature is given, and multiple instances of the application
12452a38012Sejakowatz 	are running it is undeterminate which one is chosen as the target. In case
12552a38012Sejakowatz 	only a team ID is passed, the target application is identified uniquely.
12652a38012Sejakowatz 	If both are supplied, the application identified by the team ID must have
12752a38012Sejakowatz 	a matching signature, otherwise the initilization fails.
12852a38012Sejakowatz 
12952a38012Sejakowatz 	\param signature The target application's signature. May be \c NULL.
13052a38012Sejakowatz 	\param team The target application's team ID. May be < 0.
13152a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
13252a38012Sejakowatz 		   the result of the initialization is written.
13352a38012Sejakowatz */
13452a38012Sejakowatz BMessenger::BMessenger(const char *signature, team_id team, status_t *result)
13552a38012Sejakowatz 		  : fPort(-1),
13652a38012Sejakowatz 			fHandlerToken(-1),
13752a38012Sejakowatz 			fTeam(-1),
13852a38012Sejakowatz 			fPreferredTarget(false)
13952a38012Sejakowatz {
14052a38012Sejakowatz 	InitData(signature, team, result);
14152a38012Sejakowatz }
14252a38012Sejakowatz 
14352a38012Sejakowatz // constructor
14452a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to target the local
14552a38012Sejakowatz 	BHandler and/or BLooper.
14652a38012Sejakowatz 
14752a38012Sejakowatz 	When a \c NULL handler is supplied, the preferred handler in the given
14852a38012Sejakowatz 	looper is targeted. If no looper is supplied the looper the given handler
14952a38012Sejakowatz 	belongs to is used -- that means in particular, that the handler must
15052a38012Sejakowatz 	already belong to a looper. If both are supplied the handler must actually
15152a38012Sejakowatz 	belong to looper.
15252a38012Sejakowatz 
15352a38012Sejakowatz 	\param handler The target handler. May be \c NULL.
15452a38012Sejakowatz 	\param looper The target looper. May be \c NULL.
15552a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
15652a38012Sejakowatz 		   the result of the initialization is written.
15752a38012Sejakowatz */
15852a38012Sejakowatz BMessenger::BMessenger(const BHandler *handler, const BLooper *looper,
15952a38012Sejakowatz 					   status_t *result)
16052a38012Sejakowatz 		  : fPort(-1),
16152a38012Sejakowatz 			fHandlerToken(-1),
16252a38012Sejakowatz 			fTeam(-1),
16352a38012Sejakowatz 			fPreferredTarget(false)
16452a38012Sejakowatz {
16552a38012Sejakowatz 	status_t error = (handler || looper ? B_OK : B_BAD_VALUE);
16652a38012Sejakowatz 	if (error == B_OK) {
16752a38012Sejakowatz 		if (handler) {
16852a38012Sejakowatz 			// BHandler is given, check/retrieve the looper.
16952a38012Sejakowatz 			if (looper) {
17052a38012Sejakowatz 				if (handler->Looper() != looper)
17152a38012Sejakowatz 					error = B_MISMATCHED_VALUES;
17252a38012Sejakowatz 			} else {
17352a38012Sejakowatz 				looper = handler->Looper();
17452a38012Sejakowatz 				if (looper == NULL)
17552a38012Sejakowatz 					error = B_MISMATCHED_VALUES;
17652a38012Sejakowatz 			}
17752a38012Sejakowatz 			// set port, token,...
17852a38012Sejakowatz 			if (error == B_OK) {
17952a38012Sejakowatz 				fPort = looper->fMsgPort;
18052a38012Sejakowatz 				fHandlerToken = _get_object_token_(handler);
18152a38012Sejakowatz 				fPreferredTarget = false;
18252a38012Sejakowatz 			}
18352a38012Sejakowatz 		} else {	// handler == NULL (=> looper != NULL)
18452a38012Sejakowatz 			fPort = looper->fMsgPort;
18552a38012Sejakowatz 			fHandlerToken = false;
18652a38012Sejakowatz 			fPreferredTarget = true;
18752a38012Sejakowatz 		}
18852a38012Sejakowatz 		// get and set the team ID
18952a38012Sejakowatz 		if (error == B_OK) {
19052a38012Sejakowatz 			thread_info info;
19152a38012Sejakowatz 			error = get_thread_info(find_thread(NULL), &info);
19252a38012Sejakowatz 			if (error == B_OK)
19352a38012Sejakowatz 				fTeam = info.team;
19452a38012Sejakowatz 		}
19552a38012Sejakowatz 	}
19652a38012Sejakowatz 	if (result)
19752a38012Sejakowatz 		*result = error;
19852a38012Sejakowatz }
19952a38012Sejakowatz 
20052a38012Sejakowatz // copy constructor
20152a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to have the same target
20252a38012Sejakowatz 	as the supplied messemger.
20352a38012Sejakowatz 
20452a38012Sejakowatz 	\param from The messenger to be copied.
20552a38012Sejakowatz */
20652a38012Sejakowatz BMessenger::BMessenger(const BMessenger &from)
20752a38012Sejakowatz 		  : fPort(from.fPort),
20852a38012Sejakowatz 			fHandlerToken(from.fHandlerToken),
20952a38012Sejakowatz 			fTeam(from.fTeam),
21052a38012Sejakowatz 			fPreferredTarget(from.fPreferredTarget)
21152a38012Sejakowatz {
21252a38012Sejakowatz }
21352a38012Sejakowatz 
21452a38012Sejakowatz // destructor
21552a38012Sejakowatz /*!	\brief Frees all resources associated with this object.
21652a38012Sejakowatz */
21752a38012Sejakowatz BMessenger::~BMessenger()
21852a38012Sejakowatz {
21952a38012Sejakowatz }
22052a38012Sejakowatz 
22152a38012Sejakowatz 
22252a38012Sejakowatz // Target
22352a38012Sejakowatz 
22452a38012Sejakowatz // IsTargetLocal
22552a38012Sejakowatz /*!	\brief Returns whether or not the messenger's target lives within the team
22652a38012Sejakowatz 	of the caller.
22752a38012Sejakowatz 
22852a38012Sejakowatz 	\return \c true, if the object is properly initialized and its target
22952a38012Sejakowatz 			lives within the caller's team, \c false otherwise.
23052a38012Sejakowatz */
23152a38012Sejakowatz bool
23252a38012Sejakowatz BMessenger::IsTargetLocal() const
23352a38012Sejakowatz {
23452a38012Sejakowatz 	thread_info info;
23552a38012Sejakowatz 	return (get_thread_info(find_thread(NULL), &info) == B_OK
23652a38012Sejakowatz 			&& fTeam == info.team);
23752a38012Sejakowatz }
23852a38012Sejakowatz 
23952a38012Sejakowatz // Target
24052a38012Sejakowatz /*!	\brief Returns the handler and looper targeted by the messenger, if the
24152a38012Sejakowatz 	target is local.
24252a38012Sejakowatz 
24352a38012Sejakowatz 	The handler is returned directly, the looper by reference. If both are
24452a38012Sejakowatz 	\c NULL, the object is either not properly initialized, the target
24552a38012Sejakowatz 	objects have been deleted or the target is remote. If only the returned
24652a38012Sejakowatz 	handler is \c NULL, either the looper's preferred handler is targeted or
24752a38012Sejakowatz 	the handler has been deleted.
24852a38012Sejakowatz 
24952a38012Sejakowatz 	\param looper A pointer to a pre-allocated BLooper pointer into which
25052a38012Sejakowatz 		   the pointer to the targeted looper is written.
25152a38012Sejakowatz 	\return The BHandler targeted by the messenger.
25252a38012Sejakowatz */
25352a38012Sejakowatz BHandler *
25452a38012Sejakowatz BMessenger::Target(BLooper **looper) const
25552a38012Sejakowatz {
25652a38012Sejakowatz 	BHandler *handler = NULL;
25752a38012Sejakowatz 	if (IsTargetLocal()) {
25852a38012Sejakowatz 		if (!fPreferredTarget) {
25952a38012Sejakowatz 			gDefaultTokens.GetToken(fHandlerToken, B_HANDLER_TOKEN,
26052a38012Sejakowatz 									(void**)&handler);
26152a38012Sejakowatz 		}
262e1f41e5dSIngo Weinhold 		if (looper)
263e1f41e5dSIngo Weinhold 			*looper = BPrivate::gLooperList.LooperForPort(fPort);
26452a38012Sejakowatz 	} else if (looper)
26552a38012Sejakowatz 		*looper = NULL;
26652a38012Sejakowatz 	return handler;
26752a38012Sejakowatz }
26852a38012Sejakowatz 
26952a38012Sejakowatz // LockTarget
27052a38012Sejakowatz /*!	\brief Locks the BLooper targeted by the messenger, if the target is local.
27152a38012Sejakowatz 
27252a38012Sejakowatz 	This method is a shorthand for retrieving the targeted looper via
27352a38012Sejakowatz 	Target() and calling BLooper::Lock() on the looper afterwards.
27452a38012Sejakowatz 
27552a38012Sejakowatz 	\see BLooper::Lock() for details.
27652a38012Sejakowatz 
27752a38012Sejakowatz 	\return \c true, if the looper could be locked sucessfully, \c false, if
27852a38012Sejakowatz 			the messenger is not properly initialized, the target is remote,
27952a38012Sejakowatz 			or the targeted looper is invalid.
28052a38012Sejakowatz */
28152a38012Sejakowatz bool
28252a38012Sejakowatz BMessenger::LockTarget() const
28352a38012Sejakowatz {
28452a38012Sejakowatz 	BLooper *looper = NULL;
28552a38012Sejakowatz 	Target(&looper);
28652a38012Sejakowatz 	return (looper && looper->Lock());
28752a38012Sejakowatz }
28852a38012Sejakowatz 
28952a38012Sejakowatz // LockTargetWithTimeout
29052a38012Sejakowatz /*!	\brief Locks the BLooper targeted by the messenger, if the target is local.
29152a38012Sejakowatz 
29252a38012Sejakowatz 	This method is a shorthand for retrieving the targeted looper via
29352a38012Sejakowatz 	Target() and calling BLooper::LockWithTimeout() on the looper afterwards.
29452a38012Sejakowatz 
29552a38012Sejakowatz 	\see BLooper::LockWithTimeout() for details.
29652a38012Sejakowatz 
29752a38012Sejakowatz 	\return
29852a38012Sejakowatz 	- \c B_OK, if the looper could be locked sucessfully,
29952a38012Sejakowatz 	- \c B_BAD_VALUE, if the messenger is not properly initialized,
30052a38012Sejakowatz 	  the target is remote, or the targeted looper is invalid,
30152a38012Sejakowatz 	- other error codes returned by BLooper::LockWithTimeout().
30252a38012Sejakowatz */
30352a38012Sejakowatz status_t
30452a38012Sejakowatz BMessenger::LockTargetWithTimeout(bigtime_t timeout) const
30552a38012Sejakowatz {
30652a38012Sejakowatz 	BLooper *looper = NULL;
30752a38012Sejakowatz 	Target(&looper);
30852a38012Sejakowatz 	status_t error = (looper ? B_OK : B_BAD_VALUE);
30952a38012Sejakowatz 	if (error == B_OK)
31052a38012Sejakowatz 		error = looper->LockWithTimeout(timeout);
31152a38012Sejakowatz 	return error;
31252a38012Sejakowatz }
31352a38012Sejakowatz 
31452a38012Sejakowatz 
31552a38012Sejakowatz // Message sending
31652a38012Sejakowatz 
31752a38012Sejakowatz // SendMessage
31852a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
31952a38012Sejakowatz 
3207e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
32152a38012Sejakowatz 
32252a38012Sejakowatz 	\param command The what field of the message to deliver.
32352a38012Sejakowatz 	\param replyTo The handler to which a reply to the message shall be sent.
32452a38012Sejakowatz 		   May be \c NULL.
32552a38012Sejakowatz 	\return
32652a38012Sejakowatz 	- \c B_OK: Everything went fine.
32752a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
32852a38012Sejakowatz 	  target doesn't exist anymore.
32952a38012Sejakowatz */
33052a38012Sejakowatz status_t
33152a38012Sejakowatz BMessenger::SendMessage(uint32 command, BHandler *replyTo) const
33252a38012Sejakowatz {
33352a38012Sejakowatz 	BMessage message(command);
33452a38012Sejakowatz 	return SendMessage(&message, replyTo);
33552a38012Sejakowatz }
33652a38012Sejakowatz 
33752a38012Sejakowatz // SendMessage
33852a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
33952a38012Sejakowatz 
34052a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
34152a38012Sejakowatz 	of \a message.
34252a38012Sejakowatz 
3437e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
34452a38012Sejakowatz 
34552a38012Sejakowatz 	\param message The message to be sent.
34652a38012Sejakowatz 	\param replyTo The handler to which a reply to the message shall be sent.
34752a38012Sejakowatz 		   May be \c NULL.
34852a38012Sejakowatz 	\param timeout A timeout for the delivery of the message.
34952a38012Sejakowatz 	\return
35052a38012Sejakowatz 	- \c B_OK: Everything went fine.
35152a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
35252a38012Sejakowatz 	  target doesn't exist anymore.
35352a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
35452a38012Sejakowatz 	  port was full when trying to deliver the message.
35552a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
35652a38012Sejakowatz 	  message.
35752a38012Sejakowatz */
35852a38012Sejakowatz status_t
35952a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BHandler *replyTo,
36052a38012Sejakowatz 						bigtime_t timeout) const
36152a38012Sejakowatz {
36252a38012Sejakowatz DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message->what));
36352a38012Sejakowatz 	status_t error = (message ? B_OK : B_BAD_VALUE);
36452a38012Sejakowatz 	if (error == B_OK) {
36552a38012Sejakowatz 		BMessenger replyMessenger(replyTo);
3667e24e06eSIngo Weinhold 		// If the reply messenger is invalid use the app messenger.
3677e24e06eSIngo Weinhold 		if (!replyMessenger.IsValid())
3687e24e06eSIngo Weinhold 			replyMessenger = be_app_messenger;
3697e24e06eSIngo Weinhold 		bool wantsReply = replyMessenger.IsValid();
37052a38012Sejakowatz 		error = message->_send_(fPort, fHandlerToken, fPreferredTarget,
37152a38012Sejakowatz 								timeout, wantsReply, replyMessenger);
37252a38012Sejakowatz 	}
37352a38012Sejakowatz DBG(OUT("BMessenger::SendMessage2() done: %lx\n", error));
37452a38012Sejakowatz 	return error;
37552a38012Sejakowatz }
37652a38012Sejakowatz 
37752a38012Sejakowatz // SendMessage
37852a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target.
37952a38012Sejakowatz 
38052a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
38152a38012Sejakowatz 	of \a message.
38252a38012Sejakowatz 
3837e24e06eSIngo Weinhold 	The method does not wait for a reply. The message is sent asynchronously.
38452a38012Sejakowatz 
38552a38012Sejakowatz 	\param message The message to be sent.
38652a38012Sejakowatz 	\param replyTo A messenger specifying the target for a reply to \a message.
38752a38012Sejakowatz 	\param timeout A timeout for the delivery of the message.
38852a38012Sejakowatz 	\return
38952a38012Sejakowatz 	- \c B_OK: Everything went fine.
39052a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
39152a38012Sejakowatz 	  target doesn't exist anymore.
39252a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
39352a38012Sejakowatz 	  port was full when trying to deliver the message.
39452a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
39552a38012Sejakowatz 	  message.
39652a38012Sejakowatz */
39752a38012Sejakowatz status_t
39852a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BMessenger replyTo,
39952a38012Sejakowatz 						bigtime_t timeout) const
40052a38012Sejakowatz {
40152a38012Sejakowatz 	status_t error = (message ? B_OK : B_BAD_VALUE);
40252a38012Sejakowatz 	if (error == B_OK) {
4037e24e06eSIngo Weinhold 		// If the reply messenger is invalid use the app messenger.
4047e24e06eSIngo Weinhold 		if (!replyTo.IsValid())
4057e24e06eSIngo Weinhold 			replyTo = be_app_messenger;
4067e24e06eSIngo Weinhold 		bool wantsReply = replyTo.IsValid();
40752a38012Sejakowatz 		error = message->_send_(fPort, fHandlerToken, fPreferredTarget,
4087e24e06eSIngo Weinhold 								timeout, wantsReply, replyTo);
40952a38012Sejakowatz 	}
41052a38012Sejakowatz 	return error;
41152a38012Sejakowatz }
41252a38012Sejakowatz 
41352a38012Sejakowatz // SendMessage
41452a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target and
41552a38012Sejakowatz 	waits for a reply.
41652a38012Sejakowatz 
41752a38012Sejakowatz 	The method does wait for a reply. The reply message is copied into
41852a38012Sejakowatz 	\a reply. If the target doesn't send a reply, the \c what field of
41952a38012Sejakowatz 	\a reply is set to \c B_NO_REPLY.
42052a38012Sejakowatz 
42152a38012Sejakowatz 	\param command The what field of the message to deliver.
42252a38012Sejakowatz 	\param reply A pointer to a pre-allocated BMessage into which the reply
42352a38012Sejakowatz 		   message will be copied.
42452a38012Sejakowatz 	\return
42552a38012Sejakowatz 	- \c B_OK: Everything went fine.
42652a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
42752a38012Sejakowatz 	  target doesn't exist anymore.
42852a38012Sejakowatz 	- \c B_NO_MORE_PORTS: All reply ports are in use.
42952a38012Sejakowatz */
43052a38012Sejakowatz status_t
43152a38012Sejakowatz BMessenger::SendMessage(uint32 command, BMessage *reply) const
43252a38012Sejakowatz {
43352a38012Sejakowatz 	BMessage message(command);
43452a38012Sejakowatz 	return SendMessage(&message, reply);
43552a38012Sejakowatz }
43652a38012Sejakowatz 
43752a38012Sejakowatz // SendMessage
43852a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target and
43952a38012Sejakowatz 	waits for a reply.
44052a38012Sejakowatz 
44152a38012Sejakowatz 	A copy of the supplied message is sent and the caller retains ownership
44252a38012Sejakowatz 	of \a message.
44352a38012Sejakowatz 
44452a38012Sejakowatz 	The method does wait for a reply. The reply message is copied into
44552a38012Sejakowatz 	\a reply. If the target doesn't send a reply or if a reply timeout occurs,
44652a38012Sejakowatz 	the \c what field of \a reply is set to \c B_NO_REPLY.
44752a38012Sejakowatz 
44852a38012Sejakowatz 	\param message The message to be sent.
44952a38012Sejakowatz 	\param reply A pointer to a pre-allocated BMessage into which the reply
45052a38012Sejakowatz 		   message will be copied.
45152a38012Sejakowatz 	\param deliveryTimeout A timeout for the delivery of the message.
45252a38012Sejakowatz 	\param replyTimeout A timeout for waiting for the reply.
45352a38012Sejakowatz 	\return
45452a38012Sejakowatz 	- \c B_OK: Everything went fine.
45552a38012Sejakowatz 	- \c B_BAD_PORT_ID: The messenger is not properly initialized or its
45652a38012Sejakowatz 	  target doesn't exist anymore.
45752a38012Sejakowatz 	- \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target
45852a38012Sejakowatz 	  port was full when trying to deliver the message.
45952a38012Sejakowatz 	- \c B_TIMED_OUT: The timeout expired while trying to deliver the
46052a38012Sejakowatz 	  message.
46152a38012Sejakowatz 	- \c B_NO_MORE_PORTS: All reply ports are in use.
46252a38012Sejakowatz */
46352a38012Sejakowatz status_t
46452a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BMessage *reply,
46552a38012Sejakowatz 						bigtime_t deliveryTimeout, bigtime_t replyTimeout) const
46652a38012Sejakowatz {
4678f1dc17dSIngo Weinhold 	status_t error = (message && reply ? B_OK : B_BAD_VALUE);
4688f1dc17dSIngo Weinhold 	if (error == B_OK) {
46952a38012Sejakowatz 		error = message->send_message(fPort, fTeam, fHandlerToken,
47052a38012Sejakowatz 									  fPreferredTarget, reply, deliveryTimeout,
47152a38012Sejakowatz 									  replyTimeout);
4728f1dc17dSIngo Weinhold 		// Map this error for now:
4738f1dc17dSIngo Weinhold 		if (error == B_BAD_TEAM_ID)
4748f1dc17dSIngo Weinhold 			error = B_BAD_PORT_ID;
47552a38012Sejakowatz 	}
47652a38012Sejakowatz 	return error;
47752a38012Sejakowatz }
47852a38012Sejakowatz 
47952a38012Sejakowatz 
48052a38012Sejakowatz // Operators and misc
48152a38012Sejakowatz 
48252a38012Sejakowatz // =
48352a38012Sejakowatz /*!	\brief Makes this BMessenger a copy of the supplied one.
48452a38012Sejakowatz 
48552a38012Sejakowatz 	\param from the messenger to be copied.
48652a38012Sejakowatz 	\return A reference to this object.
48752a38012Sejakowatz */
48852a38012Sejakowatz BMessenger &
48952a38012Sejakowatz BMessenger::operator=(const BMessenger &from)
49052a38012Sejakowatz {
49152a38012Sejakowatz 	if (this != &from) {
49252a38012Sejakowatz 		fPort = from.fPort;
49352a38012Sejakowatz 		fHandlerToken = from.fHandlerToken;
49452a38012Sejakowatz 		fTeam = from.fTeam;
49552a38012Sejakowatz 		fPreferredTarget = from.fPreferredTarget;
49652a38012Sejakowatz 	}
4978f1dc17dSIngo Weinhold 	return *this;
49852a38012Sejakowatz }
49952a38012Sejakowatz 
50052a38012Sejakowatz // ==
50152a38012Sejakowatz /*!	\brief Returns whether this and the supplied messenger have the same
50252a38012Sejakowatz 	target.
50352a38012Sejakowatz 
50452a38012Sejakowatz 	\param other The other messenger.
50552a38012Sejakowatz 	\return \c true, if the messengers have the same target or if both aren't
50652a38012Sejakowatz 			properly initialzed, \c false otherwise.
50752a38012Sejakowatz */
50852a38012Sejakowatz bool
50952a38012Sejakowatz BMessenger::operator==(const BMessenger &other) const
51052a38012Sejakowatz {
5118f1dc17dSIngo Weinhold 	// Note: The fTeam fields are not compared.
51252a38012Sejakowatz 	return (fPort == other.fPort
51352a38012Sejakowatz 			&& fHandlerToken == other.fHandlerToken
51452a38012Sejakowatz 			&& fPreferredTarget == other.fPreferredTarget);
51552a38012Sejakowatz }
51652a38012Sejakowatz 
51752a38012Sejakowatz // IsValid
51852a38012Sejakowatz /*!	\brief Returns whether the messenger's target looper does still exist.
51952a38012Sejakowatz 
52052a38012Sejakowatz 	It is not checked whether the target handler is also still existing.
52152a38012Sejakowatz 
52252a38012Sejakowatz 	\return \c true, if the messenger's target looper does still exist,
52352a38012Sejakowatz 			\c false otherwise.
52452a38012Sejakowatz */
52552a38012Sejakowatz bool
52652a38012Sejakowatz BMessenger::IsValid() const
52752a38012Sejakowatz {
52852a38012Sejakowatz 	port_info info;
52952a38012Sejakowatz 	return (fPort >= 0 && get_port_info(fPort, &info) == B_OK);
53052a38012Sejakowatz }
53152a38012Sejakowatz 
53252a38012Sejakowatz // Team
53352a38012Sejakowatz /*!	\brief Returns the ID of the team the messenger's target lives in.
53452a38012Sejakowatz 
53552a38012Sejakowatz 	\return The team of the messenger's target.
53652a38012Sejakowatz */
53752a38012Sejakowatz team_id
53852a38012Sejakowatz BMessenger::Team() const
53952a38012Sejakowatz {
54052a38012Sejakowatz 	return fTeam;
54152a38012Sejakowatz }
54252a38012Sejakowatz 
54352a38012Sejakowatz 
54452a38012Sejakowatz //----- Private or reserved -----------------------------------------
54552a38012Sejakowatz 
54652a38012Sejakowatz // constructor
54752a38012Sejakowatz /*!	\brief Creates a BMessenger and initializes it to team, target looper port
54852a38012Sejakowatz 	and handler token.
54952a38012Sejakowatz 
55052a38012Sejakowatz 	If \a preferred is \c true, \a token is ignored.
55152a38012Sejakowatz 
55252a38012Sejakowatz 	\param team The target's team.
55352a38012Sejakowatz 	\param port The target looper port.
55452a38012Sejakowatz 	\param token The target handler token.
55552a38012Sejakowatz 	\param preferred \c true to rather use the looper's preferred handler
55652a38012Sejakowatz 		   instead of the one specified by \a token.
55752a38012Sejakowatz */
55852a38012Sejakowatz BMessenger::BMessenger(team_id team, port_id port, int32 token, bool preferred)
55952a38012Sejakowatz 		  : fPort(-1),
56052a38012Sejakowatz 			fHandlerToken(-1),
56152a38012Sejakowatz 			fTeam(-1),
56252a38012Sejakowatz 			fPreferredTarget(false)
56352a38012Sejakowatz {
56452a38012Sejakowatz 	fTeam = team;
56552a38012Sejakowatz 	fPort = port;
56652a38012Sejakowatz 	fHandlerToken = token;
56752a38012Sejakowatz 	fPreferredTarget = preferred;
56852a38012Sejakowatz }
56952a38012Sejakowatz 
57052a38012Sejakowatz // InitData
57152a38012Sejakowatz /*!	\brief Initializes the BMessenger object's data given the signature and/or
57252a38012Sejakowatz 	team ID of a target.
57352a38012Sejakowatz 
57452a38012Sejakowatz 	When only a signature is given, and multiple instances of the application
57552a38012Sejakowatz 	are running it is undeterminate which one is chosen as the target. In case
57652a38012Sejakowatz 	only a team ID is passed, the target application is identified uniquely.
57752a38012Sejakowatz 	If both are supplied, the application identified by the team ID must have
57852a38012Sejakowatz 	a matching signature, otherwise the initilization fails.
57952a38012Sejakowatz 
58052a38012Sejakowatz 	\param signature The target application's signature. May be \c NULL.
58152a38012Sejakowatz 	\param team The target application's team ID. May be < 0.
58252a38012Sejakowatz 	\param result An optional pointer to a pre-allocated status_t into which
58352a38012Sejakowatz 		   the result of the initialization is written.
58452a38012Sejakowatz */
58552a38012Sejakowatz void
58652a38012Sejakowatz BMessenger::InitData(const char *signature, team_id team, status_t *result)
58752a38012Sejakowatz {
5883b044715SIngo Weinhold 	status_t error = B_OK;
589*9e9f5a1aSIngo Weinhold 	// get an app_info
590*9e9f5a1aSIngo Weinhold 	app_info info;
5913b044715SIngo Weinhold 	if (team < 0) {
592*9e9f5a1aSIngo Weinhold 		// no team ID given
5933b044715SIngo Weinhold 		if (signature) {
594*9e9f5a1aSIngo Weinhold 			error = be_roster->GetAppInfo(signature, &info);
595*9e9f5a1aSIngo Weinhold 			team = info.team;
596672c1ea9SIngo Weinhold 			// B_ERROR means that no application with the given signature
597672c1ea9SIngo Weinhold 			// is running. But we are supposed to return B_BAD_VALUE.
598672c1ea9SIngo Weinhold 			if (error == B_ERROR)
5993b044715SIngo Weinhold 				error = B_BAD_VALUE;
600672c1ea9SIngo Weinhold 		} else
601672c1ea9SIngo Weinhold 			error = B_BAD_TYPE;
602*9e9f5a1aSIngo Weinhold 	} else {
603*9e9f5a1aSIngo Weinhold 		// a team ID is given
6043b044715SIngo Weinhold 		error = be_roster->GetRunningAppInfo(team, &info);
605*9e9f5a1aSIngo Weinhold 		// Compare the returned signature with the supplied one.
606*9e9f5a1aSIngo Weinhold 		if (error == B_OK && signature && strcmp(signature, info.signature))
607672c1ea9SIngo Weinhold 			error = B_MISMATCHED_VALUES;
608*9e9f5a1aSIngo Weinhold 	}
609*9e9f5a1aSIngo Weinhold 	// check whether the app flags say B_ARGV_ONLY
610672c1ea9SIngo Weinhold 	if (error == B_OK && (info.flags & B_ARGV_ONLY)) {
611c9f4f5e1SIngo Weinhold 		error = B_BAD_TYPE;
612672c1ea9SIngo Weinhold 		// Set the team ID nevertheless -- that's what Be's implementation
613672c1ea9SIngo Weinhold 		// does. Don't know, if that is a bug, but at least it doesn't harm.
614672c1ea9SIngo Weinhold 		fTeam = team;
615672c1ea9SIngo Weinhold 	}
6163b044715SIngo Weinhold 	// init our members
6173b044715SIngo Weinhold 	if (error == B_OK) {
6183b044715SIngo Weinhold 		fTeam = team;
6193b044715SIngo Weinhold 		fPort = info.port;
6203b044715SIngo Weinhold 		fHandlerToken = 0;
6213b044715SIngo Weinhold 		fPreferredTarget = true;
6223b044715SIngo Weinhold 	}
6233b044715SIngo Weinhold 	// return the error
62452a38012Sejakowatz 	if (result)
6253b044715SIngo Weinhold 		*result = error;
62652a38012Sejakowatz }
62752a38012Sejakowatz 
62852a38012Sejakowatz // <
62952a38012Sejakowatz /*!	\brief Returns whether the first one of two BMessengers is less than the
63052a38012Sejakowatz 	second one.
63152a38012Sejakowatz 
63252a38012Sejakowatz 	This method defines an order on BMessengers based on their member
6338f1dc17dSIngo Weinhold 	variables \c fPort, \c fHandlerToken and \c fPreferredTarget.
6348f1dc17dSIngo Weinhold 
63552a38012Sejakowatz 	\param a The first messenger.
63652a38012Sejakowatz 	\param b The second messenger.
63752a38012Sejakowatz 	\return \c true, if \a a is less than \a b, \c false otherwise.
63852a38012Sejakowatz */
63952a38012Sejakowatz bool
64052a38012Sejakowatz operator<(const BMessenger &a, const BMessenger &b)
64152a38012Sejakowatz {
6428f1dc17dSIngo Weinhold 	// significance:
6438f1dc17dSIngo Weinhold 	// 1. fPort
6448f1dc17dSIngo Weinhold 	// 2. fHandlerToken
6458f1dc17dSIngo Weinhold 	// 3. fPreferredTarget
6468f1dc17dSIngo Weinhold 	// fTeam is insignificant
64752a38012Sejakowatz 	return (a.fPort < b.fPort
6488f1dc17dSIngo Weinhold 			|| a.fPort == b.fPort
6498f1dc17dSIngo Weinhold 				&& (a.fHandlerToken < b.fHandlerToken
6508f1dc17dSIngo Weinhold 					|| a.fHandlerToken == b.fHandlerToken
6518f1dc17dSIngo Weinhold 						&& !a.fPreferredTarget
6528f1dc17dSIngo Weinhold 						&& b.fPreferredTarget));
65352a38012Sejakowatz }
65452a38012Sejakowatz 
65552a38012Sejakowatz // !=
65652a38012Sejakowatz /*!	\brief Returns whether two BMessengers have not the same target.
65752a38012Sejakowatz 
65852a38012Sejakowatz 	\param a The first messenger.
65952a38012Sejakowatz 	\param b The second messenger.
66052a38012Sejakowatz 	\return \c false, if \a a and \a b have the same targets or are both not
66152a38012Sejakowatz 			properly initialized, \c true otherwise.
66252a38012Sejakowatz */
66352a38012Sejakowatz bool
66452a38012Sejakowatz operator!=(const BMessenger &a, const BMessenger &b)
66552a38012Sejakowatz {
66652a38012Sejakowatz 	return !(a == b);
66752a38012Sejakowatz }
66852a38012Sejakowatz 
669