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