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