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