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> 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> 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); 366*717a24b7SIngo Weinhold error = SendMessage(message, replyMessenger, timeout); 36752a38012Sejakowatz } 36852a38012Sejakowatz DBG(OUT("BMessenger::SendMessage2() done: %lx\n", error)); 36952a38012Sejakowatz return error; 37052a38012Sejakowatz } 37152a38012Sejakowatz 37252a38012Sejakowatz // SendMessage 37352a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target. 37452a38012Sejakowatz 37552a38012Sejakowatz A copy of the supplied message is sent and the caller retains ownership 37652a38012Sejakowatz of \a message. 37752a38012Sejakowatz 3787e24e06eSIngo Weinhold The method does not wait for a reply. The message is sent asynchronously. 37952a38012Sejakowatz 38052a38012Sejakowatz \param message The message to be sent. 38152a38012Sejakowatz \param replyTo A messenger specifying the target for a reply to \a message. 38252a38012Sejakowatz \param timeout A timeout for the delivery of the message. 38352a38012Sejakowatz \return 38452a38012Sejakowatz - \c B_OK: Everything went fine. 38552a38012Sejakowatz - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 38652a38012Sejakowatz target doesn't exist anymore. 38752a38012Sejakowatz - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target 38852a38012Sejakowatz port was full when trying to deliver the message. 38952a38012Sejakowatz - \c B_TIMED_OUT: The timeout expired while trying to deliver the 39052a38012Sejakowatz message. 39152a38012Sejakowatz */ 39252a38012Sejakowatz status_t 39352a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BMessenger replyTo, 39452a38012Sejakowatz bigtime_t timeout) const 39552a38012Sejakowatz { 39652a38012Sejakowatz status_t error = (message ? B_OK : B_BAD_VALUE); 39752a38012Sejakowatz if (error == B_OK) { 3987e24e06eSIngo Weinhold // If the reply messenger is invalid use the app messenger. 3997e24e06eSIngo Weinhold if (!replyTo.IsValid()) 4007e24e06eSIngo Weinhold replyTo = be_app_messenger; 40152a38012Sejakowatz error = message->_send_(fPort, fHandlerToken, fPreferredTarget, 402*717a24b7SIngo Weinhold timeout, false, replyTo); 40352a38012Sejakowatz } 40452a38012Sejakowatz return error; 40552a38012Sejakowatz } 40652a38012Sejakowatz 40752a38012Sejakowatz // SendMessage 40852a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target and 40952a38012Sejakowatz waits for a reply. 41052a38012Sejakowatz 41152a38012Sejakowatz The method does wait for a reply. The reply message is copied into 41252a38012Sejakowatz \a reply. If the target doesn't send a reply, the \c what field of 41352a38012Sejakowatz \a reply is set to \c B_NO_REPLY. 41452a38012Sejakowatz 41552a38012Sejakowatz \param command The what field of the message to deliver. 41652a38012Sejakowatz \param reply A pointer to a pre-allocated BMessage into which the reply 41752a38012Sejakowatz message will be copied. 41852a38012Sejakowatz \return 41952a38012Sejakowatz - \c B_OK: Everything went fine. 42052a38012Sejakowatz - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 42152a38012Sejakowatz target doesn't exist anymore. 42252a38012Sejakowatz - \c B_NO_MORE_PORTS: All reply ports are in use. 42352a38012Sejakowatz */ 42452a38012Sejakowatz status_t 42552a38012Sejakowatz BMessenger::SendMessage(uint32 command, BMessage *reply) const 42652a38012Sejakowatz { 42752a38012Sejakowatz BMessage message(command); 42852a38012Sejakowatz return SendMessage(&message, reply); 42952a38012Sejakowatz } 43052a38012Sejakowatz 43152a38012Sejakowatz // SendMessage 43252a38012Sejakowatz /*! \brief Delivers a BMessage synchronously to the messenger's target and 43352a38012Sejakowatz waits for a reply. 43452a38012Sejakowatz 43552a38012Sejakowatz A copy of the supplied message is sent and the caller retains ownership 43652a38012Sejakowatz of \a message. 43752a38012Sejakowatz 43852a38012Sejakowatz The method does wait for a reply. The reply message is copied into 43952a38012Sejakowatz \a reply. If the target doesn't send a reply or if a reply timeout occurs, 44052a38012Sejakowatz the \c what field of \a reply is set to \c B_NO_REPLY. 44152a38012Sejakowatz 44252a38012Sejakowatz \param message The message to be sent. 44352a38012Sejakowatz \param reply A pointer to a pre-allocated BMessage into which the reply 44452a38012Sejakowatz message will be copied. 44552a38012Sejakowatz \param deliveryTimeout A timeout for the delivery of the message. 44652a38012Sejakowatz \param replyTimeout A timeout for waiting for the reply. 44752a38012Sejakowatz \return 44852a38012Sejakowatz - \c B_OK: Everything went fine. 44952a38012Sejakowatz - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 45052a38012Sejakowatz target doesn't exist anymore. 45152a38012Sejakowatz - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target 45252a38012Sejakowatz port was full when trying to deliver the message. 45352a38012Sejakowatz - \c B_TIMED_OUT: The timeout expired while trying to deliver the 45452a38012Sejakowatz message. 45552a38012Sejakowatz - \c B_NO_MORE_PORTS: All reply ports are in use. 45652a38012Sejakowatz */ 45752a38012Sejakowatz status_t 45852a38012Sejakowatz BMessenger::SendMessage(BMessage *message, BMessage *reply, 45952a38012Sejakowatz bigtime_t deliveryTimeout, bigtime_t replyTimeout) const 46052a38012Sejakowatz { 4618f1dc17dSIngo Weinhold status_t error = (message && reply ? B_OK : B_BAD_VALUE); 4628f1dc17dSIngo Weinhold if (error == B_OK) { 46352a38012Sejakowatz error = message->send_message(fPort, fTeam, fHandlerToken, 46452a38012Sejakowatz fPreferredTarget, reply, deliveryTimeout, 46552a38012Sejakowatz replyTimeout); 4668f1dc17dSIngo Weinhold // Map this error for now: 4678f1dc17dSIngo Weinhold if (error == B_BAD_TEAM_ID) 4688f1dc17dSIngo Weinhold error = B_BAD_PORT_ID; 46952a38012Sejakowatz } 47052a38012Sejakowatz return error; 47152a38012Sejakowatz } 47252a38012Sejakowatz 47352a38012Sejakowatz 47452a38012Sejakowatz // Operators and misc 47552a38012Sejakowatz 47652a38012Sejakowatz // = 47752a38012Sejakowatz /*! \brief Makes this BMessenger a copy of the supplied one. 47852a38012Sejakowatz 47952a38012Sejakowatz \param from the messenger to be copied. 48052a38012Sejakowatz \return A reference to this object. 48152a38012Sejakowatz */ 48252a38012Sejakowatz BMessenger & 48352a38012Sejakowatz BMessenger::operator=(const BMessenger &from) 48452a38012Sejakowatz { 48552a38012Sejakowatz if (this != &from) { 48652a38012Sejakowatz fPort = from.fPort; 48752a38012Sejakowatz fHandlerToken = from.fHandlerToken; 48852a38012Sejakowatz fTeam = from.fTeam; 48952a38012Sejakowatz fPreferredTarget = from.fPreferredTarget; 49052a38012Sejakowatz } 4918f1dc17dSIngo Weinhold return *this; 49252a38012Sejakowatz } 49352a38012Sejakowatz 49452a38012Sejakowatz // == 49552a38012Sejakowatz /*! \brief Returns whether this and the supplied messenger have the same 49652a38012Sejakowatz target. 49752a38012Sejakowatz 49852a38012Sejakowatz \param other The other messenger. 49952a38012Sejakowatz \return \c true, if the messengers have the same target or if both aren't 50052a38012Sejakowatz properly initialzed, \c false otherwise. 50152a38012Sejakowatz */ 50252a38012Sejakowatz bool 50352a38012Sejakowatz BMessenger::operator==(const BMessenger &other) const 50452a38012Sejakowatz { 5058f1dc17dSIngo Weinhold // Note: The fTeam fields are not compared. 50652a38012Sejakowatz return (fPort == other.fPort 50752a38012Sejakowatz && fHandlerToken == other.fHandlerToken 50852a38012Sejakowatz && fPreferredTarget == other.fPreferredTarget); 50952a38012Sejakowatz } 51052a38012Sejakowatz 51152a38012Sejakowatz // IsValid 51252a38012Sejakowatz /*! \brief Returns whether the messenger's target looper does still exist. 51352a38012Sejakowatz 51452a38012Sejakowatz It is not checked whether the target handler is also still existing. 51552a38012Sejakowatz 51652a38012Sejakowatz \return \c true, if the messenger's target looper does still exist, 51752a38012Sejakowatz \c false otherwise. 51852a38012Sejakowatz */ 51952a38012Sejakowatz bool 52052a38012Sejakowatz BMessenger::IsValid() const 52152a38012Sejakowatz { 52252a38012Sejakowatz port_info info; 52352a38012Sejakowatz return (fPort >= 0 && get_port_info(fPort, &info) == B_OK); 52452a38012Sejakowatz } 52552a38012Sejakowatz 52652a38012Sejakowatz // Team 52752a38012Sejakowatz /*! \brief Returns the ID of the team the messenger's target lives in. 52852a38012Sejakowatz 52952a38012Sejakowatz \return The team of the messenger's target. 53052a38012Sejakowatz */ 53152a38012Sejakowatz team_id 53252a38012Sejakowatz BMessenger::Team() const 53352a38012Sejakowatz { 53452a38012Sejakowatz return fTeam; 53552a38012Sejakowatz } 53652a38012Sejakowatz 53752a38012Sejakowatz 53852a38012Sejakowatz //----- Private or reserved ----------------------------------------- 53952a38012Sejakowatz 54052a38012Sejakowatz // constructor 54152a38012Sejakowatz /*! \brief Creates a BMessenger and initializes it to team, target looper port 54252a38012Sejakowatz and handler token. 54352a38012Sejakowatz 54452a38012Sejakowatz If \a preferred is \c true, \a token is ignored. 54552a38012Sejakowatz 54652a38012Sejakowatz \param team The target's team. 54752a38012Sejakowatz \param port The target looper port. 54852a38012Sejakowatz \param token The target handler token. 54952a38012Sejakowatz \param preferred \c true to rather use the looper's preferred handler 55052a38012Sejakowatz instead of the one specified by \a token. 55152a38012Sejakowatz */ 55252a38012Sejakowatz BMessenger::BMessenger(team_id team, port_id port, int32 token, bool preferred) 55352a38012Sejakowatz : fPort(-1), 55452a38012Sejakowatz fHandlerToken(-1), 55552a38012Sejakowatz fTeam(-1), 55652a38012Sejakowatz fPreferredTarget(false) 55752a38012Sejakowatz { 55852a38012Sejakowatz fTeam = team; 55952a38012Sejakowatz fPort = port; 56052a38012Sejakowatz fHandlerToken = token; 56152a38012Sejakowatz fPreferredTarget = preferred; 56252a38012Sejakowatz } 56352a38012Sejakowatz 56452a38012Sejakowatz // InitData 56552a38012Sejakowatz /*! \brief Initializes the BMessenger object's data given the signature and/or 56652a38012Sejakowatz team ID of a target. 56752a38012Sejakowatz 56852a38012Sejakowatz When only a signature is given, and multiple instances of the application 56952a38012Sejakowatz are running it is undeterminate which one is chosen as the target. In case 57052a38012Sejakowatz only a team ID is passed, the target application is identified uniquely. 57152a38012Sejakowatz If both are supplied, the application identified by the team ID must have 57252a38012Sejakowatz a matching signature, otherwise the initilization fails. 57352a38012Sejakowatz 57452a38012Sejakowatz \param signature The target application's signature. May be \c NULL. 57552a38012Sejakowatz \param team The target application's team ID. May be < 0. 57652a38012Sejakowatz \param result An optional pointer to a pre-allocated status_t into which 57752a38012Sejakowatz the result of the initialization is written. 57852a38012Sejakowatz */ 57952a38012Sejakowatz void 58052a38012Sejakowatz BMessenger::InitData(const char *signature, team_id team, status_t *result) 58152a38012Sejakowatz { 5823b044715SIngo Weinhold status_t error = B_OK; 5839e9f5a1aSIngo Weinhold // get an app_info 5849e9f5a1aSIngo Weinhold app_info info; 5853b044715SIngo Weinhold if (team < 0) { 5869e9f5a1aSIngo Weinhold // no team ID given 5873b044715SIngo Weinhold if (signature) { 5889e9f5a1aSIngo Weinhold error = be_roster->GetAppInfo(signature, &info); 5899e9f5a1aSIngo Weinhold team = info.team; 590672c1ea9SIngo Weinhold // B_ERROR means that no application with the given signature 591672c1ea9SIngo Weinhold // is running. But we are supposed to return B_BAD_VALUE. 592672c1ea9SIngo Weinhold if (error == B_ERROR) 5933b044715SIngo Weinhold error = B_BAD_VALUE; 594672c1ea9SIngo Weinhold } else 595672c1ea9SIngo Weinhold error = B_BAD_TYPE; 5969e9f5a1aSIngo Weinhold } else { 5979e9f5a1aSIngo Weinhold // a team ID is given 5983b044715SIngo Weinhold error = be_roster->GetRunningAppInfo(team, &info); 5999e9f5a1aSIngo Weinhold // Compare the returned signature with the supplied one. 6009e9f5a1aSIngo Weinhold if (error == B_OK && signature && strcmp(signature, info.signature)) 601672c1ea9SIngo Weinhold error = B_MISMATCHED_VALUES; 6029e9f5a1aSIngo Weinhold } 6039e9f5a1aSIngo Weinhold // check whether the app flags say B_ARGV_ONLY 604672c1ea9SIngo Weinhold if (error == B_OK && (info.flags & B_ARGV_ONLY)) { 605c9f4f5e1SIngo Weinhold error = B_BAD_TYPE; 606672c1ea9SIngo Weinhold // Set the team ID nevertheless -- that's what Be's implementation 607672c1ea9SIngo Weinhold // does. Don't know, if that is a bug, but at least it doesn't harm. 608672c1ea9SIngo Weinhold fTeam = team; 609672c1ea9SIngo Weinhold } 6103b044715SIngo Weinhold // init our members 6113b044715SIngo Weinhold if (error == B_OK) { 6123b044715SIngo Weinhold fTeam = team; 6133b044715SIngo Weinhold fPort = info.port; 6143b044715SIngo Weinhold fHandlerToken = 0; 6153b044715SIngo Weinhold fPreferredTarget = true; 6163b044715SIngo Weinhold } 6173b044715SIngo Weinhold // return the error 61852a38012Sejakowatz if (result) 6193b044715SIngo Weinhold *result = error; 62052a38012Sejakowatz } 62152a38012Sejakowatz 62252a38012Sejakowatz // < 62352a38012Sejakowatz /*! \brief Returns whether the first one of two BMessengers is less than the 62452a38012Sejakowatz second one. 62552a38012Sejakowatz 62652a38012Sejakowatz This method defines an order on BMessengers based on their member 6278f1dc17dSIngo Weinhold variables \c fPort, \c fHandlerToken and \c fPreferredTarget. 6288f1dc17dSIngo Weinhold 62952a38012Sejakowatz \param a The first messenger. 63052a38012Sejakowatz \param b The second messenger. 63152a38012Sejakowatz \return \c true, if \a a is less than \a b, \c false otherwise. 63252a38012Sejakowatz */ 63352a38012Sejakowatz bool 63452a38012Sejakowatz operator<(const BMessenger &a, const BMessenger &b) 63552a38012Sejakowatz { 6368f1dc17dSIngo Weinhold // significance: 6378f1dc17dSIngo Weinhold // 1. fPort 6388f1dc17dSIngo Weinhold // 2. fHandlerToken 6398f1dc17dSIngo Weinhold // 3. fPreferredTarget 6408f1dc17dSIngo Weinhold // fTeam is insignificant 64152a38012Sejakowatz return (a.fPort < b.fPort 6428f1dc17dSIngo Weinhold || a.fPort == b.fPort 6438f1dc17dSIngo Weinhold && (a.fHandlerToken < b.fHandlerToken 6448f1dc17dSIngo Weinhold || a.fHandlerToken == b.fHandlerToken 6458f1dc17dSIngo Weinhold && !a.fPreferredTarget 6468f1dc17dSIngo Weinhold && b.fPreferredTarget)); 64752a38012Sejakowatz } 64852a38012Sejakowatz 64952a38012Sejakowatz // != 65052a38012Sejakowatz /*! \brief Returns whether two BMessengers have not the same target. 65152a38012Sejakowatz 65252a38012Sejakowatz \param a The first messenger. 65352a38012Sejakowatz \param b The second messenger. 65452a38012Sejakowatz \return \c false, if \a a and \a b have the same targets or are both not 65552a38012Sejakowatz properly initialized, \c true otherwise. 65652a38012Sejakowatz */ 65752a38012Sejakowatz bool 65852a38012Sejakowatz operator!=(const BMessenger &a, const BMessenger &b) 65952a38012Sejakowatz { 66052a38012Sejakowatz return !(a == b); 66152a38012Sejakowatz } 66252a38012Sejakowatz 663