1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2005, Haiku 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Messenger.h 23 // Author: Ingo Weinhold (bonefish@users.sf.net) 24 // Description: BMessenger delivers messages to local or remote targets. 25 //------------------------------------------------------------------------------ 26 27 // debugging 28 //#define DBG(x) x 29 #define DBG(x) 30 #define OUT printf 31 32 // Standard Includes ----------------------------------------------------------- 33 #include <new> 34 #include <stdio.h> 35 #include <string.h> 36 37 // System Includes ------------------------------------------------------------- 38 #include <Application.h> 39 #include <Handler.h> 40 #include <Looper.h> 41 #include <LooperList.h> 42 #include <Message.h> 43 #include <Messenger.h> 44 #include <OS.h> 45 #include <Roster.h> 46 #include <TokenSpace.h> 47 48 // Project Includes ------------------------------------------------------------ 49 #include <AppMisc.h> 50 #include <MessageUtils.h> 51 #include "ObjectLocker.h" 52 #include "TokenSpace.h" 53 54 #ifdef USING_MESSAGE4 55 #include <MessagePrivate.h> 56 #endif 57 58 // Local Includes -------------------------------------------------------------- 59 60 // Local Defines --------------------------------------------------------------- 61 62 // Globals --------------------------------------------------------------------- 63 64 using BPrivate::gDefaultTokens; 65 using BPrivate::gLooperList; 66 using BPrivate::BLooperList; 67 using BPrivate::BObjectLocker; 68 69 enum { 70 NOT_IMPLEMENTED = B_ERROR, 71 }; 72 73 74 // constructor 75 /*! \brief Creates an unitialized BMessenger. 76 */ 77 BMessenger::BMessenger() 78 : fPort(-1), 79 fHandlerToken(B_NULL_TOKEN), 80 fTeam(-1), 81 fPreferredTarget(false) 82 { 83 } 84 85 // constructor 86 /*! \brief Creates a BMessenger and initializes it to target the already 87 running application identified by its signature and/or team ID. 88 89 When only a signature is given, and multiple instances of the application 90 are running it is undeterminate which one is chosen as the target. In case 91 only a team ID is passed, the target application is identified uniquely. 92 If both are supplied, the application identified by the team ID must have 93 a matching signature, otherwise the initilization fails. 94 95 \param signature The target application's signature. May be \c NULL. 96 \param team The target application's team ID. May be < 0. 97 \param result An optional pointer to a pre-allocated status_t into which 98 the result of the initialization is written. 99 */ 100 BMessenger::BMessenger(const char *signature, team_id team, status_t *result) 101 : fPort(-1), 102 fHandlerToken(B_NULL_TOKEN), 103 fTeam(-1), 104 fPreferredTarget(false) 105 { 106 InitData(signature, team, result); 107 } 108 109 // constructor 110 /*! \brief Creates a BMessenger and initializes it to target the local 111 BHandler and/or BLooper. 112 113 When a \c NULL handler is supplied, the preferred handler in the given 114 looper is targeted. If no looper is supplied the looper the given handler 115 belongs to is used -- that means in particular, that the handler must 116 already belong to a looper. If both are supplied the handler must actually 117 belong to looper. 118 119 \param handler The target handler. May be \c NULL. 120 \param looper The target looper. May be \c NULL. 121 \param result An optional pointer to a pre-allocated status_t into which 122 the result of the initialization is written. 123 */ 124 BMessenger::BMessenger(const BHandler *handler, const BLooper *looper, 125 status_t *result) 126 : fPort(-1), 127 fHandlerToken(B_NULL_TOKEN), 128 fTeam(-1), 129 fPreferredTarget(false) 130 { 131 status_t error = (handler || looper ? B_OK : B_BAD_VALUE); 132 if (error == B_OK) { 133 if (handler) { 134 // BHandler is given, check/retrieve the looper. 135 if (looper) { 136 if (handler->Looper() != looper) 137 error = B_MISMATCHED_VALUES; 138 } else { 139 looper = handler->Looper(); 140 if (looper == NULL) 141 error = B_MISMATCHED_VALUES; 142 } 143 } 144 // set port, token,... 145 if (error == B_OK) { 146 BObjectLocker<BLooperList> locker(gLooperList); 147 if (locker.IsLocked() && gLooperList.IsLooperValid(looper)) { 148 fPort = looper->fMsgPort; 149 fHandlerToken = (handler 150 ? _get_object_token_(handler) : B_PREFERRED_TOKEN); 151 fPreferredTarget = !handler; 152 fTeam = looper->Team(); 153 } else 154 error = B_BAD_VALUE; 155 } 156 } 157 if (result) 158 *result = error; 159 } 160 161 // copy constructor 162 /*! \brief Creates a BMessenger and initializes it to have the same target 163 as the supplied messemger. 164 165 \param from The messenger to be copied. 166 */ 167 BMessenger::BMessenger(const BMessenger &from) 168 : fPort(from.fPort), 169 fHandlerToken(from.fHandlerToken), 170 fTeam(from.fTeam), 171 fPreferredTarget(from.fPreferredTarget) 172 { 173 } 174 175 // destructor 176 /*! \brief Frees all resources associated with this object. 177 */ 178 BMessenger::~BMessenger() 179 { 180 } 181 182 183 // Target 184 185 // IsTargetLocal 186 /*! \brief Returns whether or not the messenger's target lives within the team 187 of the caller. 188 189 \return \c true, if the object is properly initialized and its target 190 lives within the caller's team, \c false otherwise. 191 */ 192 bool 193 BMessenger::IsTargetLocal() const 194 { 195 thread_info info; 196 return (get_thread_info(find_thread(NULL), &info) == B_OK 197 && fTeam == info.team); 198 } 199 200 // Target 201 /*! \brief Returns the handler and looper targeted by the messenger, if the 202 target is local. 203 204 The handler is returned directly, the looper by reference. If both are 205 \c NULL, the object is either not properly initialized, the target 206 objects have been deleted or the target is remote. If only the returned 207 handler is \c NULL, either the looper's preferred handler is targeted or 208 the handler has been deleted. 209 210 \param looper A pointer to a pre-allocated BLooper pointer into which 211 the pointer to the targeted looper is written. 212 \return The BHandler targeted by the messenger. 213 */ 214 BHandler * 215 BMessenger::Target(BLooper **looper) const 216 { 217 BHandler *handler = NULL; 218 if (IsTargetLocal()) { 219 if (!fPreferredTarget) { 220 gDefaultTokens.GetToken(fHandlerToken, B_HANDLER_TOKEN, 221 (void**)&handler); 222 } 223 if (looper) 224 *looper = BPrivate::gLooperList.LooperForPort(fPort); 225 } else if (looper) 226 *looper = NULL; 227 return handler; 228 } 229 230 // LockTarget 231 /*! \brief Locks the BLooper targeted by the messenger, if the target is local. 232 233 This method is a shorthand for retrieving the targeted looper via 234 Target() and calling BLooper::Lock() on the looper afterwards. 235 236 \see BLooper::Lock() for details. 237 238 \return \c true, if the looper could be locked sucessfully, \c false, if 239 the messenger is not properly initialized, the target is remote, 240 or the targeted looper is invalid. 241 */ 242 bool 243 BMessenger::LockTarget() const 244 { 245 BLooper *looper = NULL; 246 Target(&looper); 247 return (looper && looper->Lock()); 248 } 249 250 // LockTargetWithTimeout 251 /*! \brief Locks the BLooper targeted by the messenger, if the target is local. 252 253 This method is a shorthand for retrieving the targeted looper via 254 Target() and calling BLooper::LockWithTimeout() on the looper afterwards. 255 256 \see BLooper::LockWithTimeout() for details. 257 258 \return 259 - \c B_OK, if the looper could be locked sucessfully, 260 - \c B_BAD_VALUE, if the messenger is not properly initialized, 261 the target is remote, or the targeted looper is invalid, 262 - other error codes returned by BLooper::LockWithTimeout(). 263 */ 264 status_t 265 BMessenger::LockTargetWithTimeout(bigtime_t timeout) const 266 { 267 BLooper *looper = NULL; 268 Target(&looper); 269 status_t error = (looper ? B_OK : B_BAD_VALUE); 270 if (error == B_OK) 271 error = looper->LockWithTimeout(timeout); 272 return error; 273 } 274 275 276 // Message sending 277 278 // SendMessage 279 /*! \brief Delivers a BMessage synchronously to the messenger's target. 280 281 The method does not wait for a reply. The message is sent asynchronously. 282 283 \param command The what field of the message to deliver. 284 \param replyTo The handler to which a reply to the message shall be sent. 285 May be \c NULL. 286 \return 287 - \c B_OK: Everything went fine. 288 - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 289 target doesn't exist anymore. 290 */ 291 status_t 292 BMessenger::SendMessage(uint32 command, BHandler *replyTo) const 293 { 294 BMessage message(command); 295 return SendMessage(&message, replyTo); 296 } 297 298 // SendMessage 299 /*! \brief Delivers a BMessage synchronously to the messenger's target. 300 301 A copy of the supplied message is sent and the caller retains ownership 302 of \a message. 303 304 The method does not wait for a reply. The message is sent asynchronously. 305 306 \param message The message to be sent. 307 \param replyTo The handler to which a reply to the message shall be sent. 308 May be \c NULL. 309 \param timeout A timeout for the delivery of the message. 310 \return 311 - \c B_OK: Everything went fine. 312 - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 313 target doesn't exist anymore. 314 - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target 315 port was full when trying to deliver the message. 316 - \c B_TIMED_OUT: The timeout expired while trying to deliver the 317 message. 318 */ 319 status_t 320 BMessenger::SendMessage(BMessage *message, BHandler *replyTo, 321 bigtime_t timeout) const 322 { 323 DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message->what)); 324 status_t error = (message ? B_OK : B_BAD_VALUE); 325 if (error == B_OK) { 326 BMessenger replyMessenger(replyTo); 327 error = SendMessage(message, replyMessenger, timeout); 328 } 329 DBG(OUT("BMessenger::SendMessage2() done: %lx\n", error)); 330 return error; 331 } 332 333 // SendMessage 334 /*! \brief Delivers a BMessage synchronously to the messenger's target. 335 336 A copy of the supplied message is sent and the caller retains ownership 337 of \a message. 338 339 The method does not wait for a reply. The message is sent asynchronously. 340 341 \param message The message to be sent. 342 \param replyTo A messenger specifying the target for a reply to \a message. 343 \param timeout A timeout for the delivery of the message. 344 \return 345 - \c B_OK: Everything went fine. 346 - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 347 target doesn't exist anymore. 348 - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target 349 port was full when trying to deliver the message. 350 - \c B_TIMED_OUT: The timeout expired while trying to deliver the 351 message. 352 */ 353 status_t 354 BMessenger::SendMessage(BMessage *message, BMessenger replyTo, 355 bigtime_t timeout) const 356 { 357 if (!message) 358 return B_BAD_VALUE; 359 360 #ifndef USING_MESSAGE4 361 return message->_send_(fPort, fHandlerToken, fPreferredTarget, 362 timeout, false, replyTo); 363 #else 364 return BMessage::Private(message).SendMessage(fPort, fHandlerToken, 365 fPreferredTarget, timeout, false, replyTo); 366 #endif 367 } 368 369 // SendMessage 370 /*! \brief Delivers a BMessage synchronously to the messenger's target and 371 waits for a reply. 372 373 The method does wait for a reply. The reply message is copied into 374 \a reply. If the target doesn't send a reply, the \c what field of 375 \a reply is set to \c B_NO_REPLY. 376 377 \param command The what field of the message to deliver. 378 \param reply A pointer to a pre-allocated BMessage into which the reply 379 message will be copied. 380 \return 381 - \c B_OK: Everything went fine. 382 - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 383 target doesn't exist anymore. 384 - \c B_NO_MORE_PORTS: All reply ports are in use. 385 */ 386 status_t 387 BMessenger::SendMessage(uint32 command, BMessage *reply) const 388 { 389 BMessage message(command); 390 return SendMessage(&message, reply); 391 } 392 393 // SendMessage 394 /*! \brief Delivers a BMessage synchronously to the messenger's target and 395 waits for a reply. 396 397 A copy of the supplied message is sent and the caller retains ownership 398 of \a message. 399 400 The method does wait for a reply. The reply message is copied into 401 \a reply. If the target doesn't send a reply or if a reply timeout occurs, 402 the \c what field of \a reply is set to \c B_NO_REPLY. 403 404 \param message The message to be sent. 405 \param reply A pointer to a pre-allocated BMessage into which the reply 406 message will be copied. 407 \param deliveryTimeout A timeout for the delivery of the message. 408 \param replyTimeout A timeout for waiting for the reply. 409 \return 410 - \c B_OK: Everything went fine. 411 - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 412 target doesn't exist anymore. 413 - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target 414 port was full when trying to deliver the message. 415 - \c B_TIMED_OUT: The timeout expired while trying to deliver the 416 message. 417 - \c B_NO_MORE_PORTS: All reply ports are in use. 418 */ 419 status_t 420 BMessenger::SendMessage(BMessage *message, BMessage *reply, 421 bigtime_t deliveryTimeout, bigtime_t replyTimeout) const 422 { 423 status_t error = (message && reply ? B_OK : B_BAD_VALUE); 424 if (error == B_OK) { 425 #ifndef USING_MESSAGE4 426 error = message->send_message(fPort, fTeam, fHandlerToken, 427 fPreferredTarget, reply, deliveryTimeout, 428 replyTimeout); 429 #else 430 error = BMessage::Private(message).SendMessage(fPort, fTeam, 431 fHandlerToken, fPreferredTarget, reply, deliveryTimeout, 432 replyTimeout); 433 #endif 434 // Map this error for now: 435 if (error == B_BAD_TEAM_ID) 436 error = B_BAD_PORT_ID; 437 } 438 return error; 439 } 440 441 442 // Operators and misc 443 444 // = 445 /*! \brief Makes this BMessenger a copy of the supplied one. 446 447 \param from the messenger to be copied. 448 \return A reference to this object. 449 */ 450 BMessenger & 451 BMessenger::operator=(const BMessenger &from) 452 { 453 if (this != &from) { 454 fPort = from.fPort; 455 fHandlerToken = from.fHandlerToken; 456 fTeam = from.fTeam; 457 fPreferredTarget = from.fPreferredTarget; 458 } 459 return *this; 460 } 461 462 // == 463 /*! \brief Returns whether this and the supplied messenger have the same 464 target. 465 466 \param other The other messenger. 467 \return \c true, if the messengers have the same target or if both aren't 468 properly initialzed, \c false otherwise. 469 */ 470 bool 471 BMessenger::operator==(const BMessenger &other) const 472 { 473 // Note: The fTeam fields are not compared. 474 return (fPort == other.fPort 475 && fHandlerToken == other.fHandlerToken 476 && fPreferredTarget == other.fPreferredTarget); 477 } 478 479 // IsValid 480 /*! \brief Returns whether the messenger's target looper does still exist. 481 482 It is not checked whether the target handler is also still existing. 483 484 \return \c true, if the messenger's target looper does still exist, 485 \c false otherwise. 486 */ 487 bool 488 BMessenger::IsValid() const 489 { 490 port_info info; 491 return (fPort >= 0 && get_port_info(fPort, &info) == B_OK); 492 } 493 494 // Team 495 /*! \brief Returns the ID of the team the messenger's target lives in. 496 497 \return The team of the messenger's target. 498 */ 499 team_id 500 BMessenger::Team() const 501 { 502 return fTeam; 503 } 504 505 506 //----- Private or reserved ----------------------------------------- 507 508 // SetTo 509 /*! \brief Sets the messenger's team, target looper port and handler token. 510 511 If \a preferred is \c true, \a token is ignored. 512 513 \param team The target's team. 514 \param port The target looper port. 515 \param token The target handler token. 516 \param preferred \c true to rather use the looper's preferred handler 517 instead of the one specified by \a token. 518 */ 519 void 520 BMessenger::SetTo(team_id team, port_id port, int32 token, bool preferred) 521 { 522 fTeam = team; 523 fPort = port; 524 fHandlerToken = (preferred ? B_PREFERRED_TOKEN : token); 525 fPreferredTarget = preferred; 526 } 527 528 // InitData 529 /*! \brief Initializes the BMessenger object's data given the signature and/or 530 team ID of a target. 531 532 When only a signature is given, and multiple instances of the application 533 are running it is undeterminate which one is chosen as the target. In case 534 only a team ID is passed, the target application is identified uniquely. 535 If both are supplied, the application identified by the team ID must have 536 a matching signature, otherwise the initilization fails. 537 538 \param signature The target application's signature. May be \c NULL. 539 \param team The target application's team ID. May be < 0. 540 \param result An optional pointer to a pre-allocated status_t into which 541 the result of the initialization is written. 542 */ 543 void 544 BMessenger::InitData(const char *signature, team_id team, status_t *result) 545 { 546 status_t error = B_OK; 547 // get an app_info 548 app_info info; 549 if (team < 0) { 550 // no team ID given 551 if (signature) { 552 error = be_roster->GetAppInfo(signature, &info); 553 team = info.team; 554 // B_ERROR means that no application with the given signature 555 // is running. But we are supposed to return B_BAD_VALUE. 556 if (error == B_ERROR) 557 error = B_BAD_VALUE; 558 } else 559 error = B_BAD_TYPE; 560 } else { 561 // a team ID is given 562 error = be_roster->GetRunningAppInfo(team, &info); 563 // Compare the returned signature with the supplied one. 564 if (error == B_OK && signature && strcasecmp(signature, info.signature)) 565 error = B_MISMATCHED_VALUES; 566 } 567 // check whether the app flags say B_ARGV_ONLY 568 if (error == B_OK && (info.flags & B_ARGV_ONLY)) { 569 error = B_BAD_TYPE; 570 // Set the team ID nevertheless -- that's what Be's implementation 571 // does. Don't know, if that is a bug, but at least it doesn't harm. 572 fTeam = team; 573 } 574 // init our members 575 if (error == B_OK) { 576 fTeam = team; 577 fPort = info.port; 578 fHandlerToken = B_PREFERRED_TOKEN; 579 fPreferredTarget = true; 580 } 581 // return the error 582 if (result) 583 *result = error; 584 } 585 586 // < 587 /*! \brief Returns whether the first one of two BMessengers is less than the 588 second one. 589 590 This method defines an order on BMessengers based on their member 591 variables \c fPort, \c fHandlerToken and \c fPreferredTarget. 592 593 \param a The first messenger. 594 \param b The second messenger. 595 \return \c true, if \a a is less than \a b, \c false otherwise. 596 */ 597 bool 598 operator<(const BMessenger &_a, const BMessenger &_b) 599 { 600 BMessenger::Private a(const_cast<BMessenger&>(_a)); 601 BMessenger::Private b(const_cast<BMessenger&>(_b)); 602 603 604 // significance: 605 // 1. fPort 606 // 2. fHandlerToken 607 // 3. fPreferredTarget 608 // fTeam is insignificant 609 return (a.Port() < b.Port() 610 || a.Port() == b.Port() 611 && (a.Token() < b.Token() 612 || a.Token() == b.Token() 613 && !a.IsPreferredTarget() 614 && b.IsPreferredTarget())); 615 } 616 617 // != 618 /*! \brief Returns whether two BMessengers have not the same target. 619 620 \param a The first messenger. 621 \param b The second messenger. 622 \return \c false, if \a a and \a b have the same targets or are both not 623 properly initialized, \c true otherwise. 624 */ 625 bool 626 operator!=(const BMessenger &a, const BMessenger &b) 627 { 628 return !(a == b); 629 } 630 631