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 250 The method does not wait for a reply. The message is sent asynchronously. 251 252 \param command The what field of the message to deliver. 253 \param replyTo The handler to which a reply to the message shall be sent. 254 May be \c NULL. 255 \return 256 - \c B_OK: Everything went fine. 257 - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 258 target doesn't exist anymore. 259 */ 260 status_t 261 BMessenger::SendMessage(uint32 command, BHandler *replyTo) const 262 { 263 BMessage message(command); 264 return SendMessage(&message, replyTo); 265 } 266 267 // SendMessage 268 /*! \brief Delivers a BMessage synchronously to the messenger's target. 269 270 A copy of the supplied message is sent and the caller retains ownership 271 of \a message. 272 273 The method does not wait for a reply. The message is sent asynchronously. 274 275 \param message The message to be sent. 276 \param replyTo The handler to which a reply to the message shall be sent. 277 May be \c NULL. 278 \param timeout A timeout for the delivery of the message. 279 \return 280 - \c B_OK: Everything went fine. 281 - \c B_BAD_PORT_ID: The messenger is not properly initialized or its 282 target doesn't exist anymore. 283 - \c B_WOULD_BLOCK: A delivery timeout of 0 was supplied and the target 284 port was full when trying to deliver the message. 285 - \c B_TIMED_OUT: The timeout expired while trying to deliver the 286 message. 287 */ 288 status_t 289 BMessenger::SendMessage(BMessage *message, BHandler *replyTo, 290 bigtime_t timeout) const 291 { 292 DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message->what)); 293 status_t error = (message ? B_OK : B_BAD_VALUE); 294 if (error == B_OK) { 295 BMessenger replyMessenger(replyTo); 296 error = SendMessage(message, replyMessenger, timeout); 297 } 298 DBG(OUT("BMessenger::SendMessage2() done: %lx\n", error)); 299 return error; 300 } 301 302 // SendMessage 303 /*! \brief Delivers a BMessage synchronously to the messenger's target. 304 305 A copy of the supplied message is sent and the caller retains ownership 306 of \a message. 307 308 The method does not wait for a reply. The message is sent asynchronously. 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 // SendMessage 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 // SendMessage 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 Makes this BMessenger a copy of the supplied one. 405 406 \param from the messenger to be copied. 407 \return A reference to this object. 408 */ 409 BMessenger & 410 BMessenger::operator=(const BMessenger &from) 411 { 412 if (this != &from) { 413 fPort = from.fPort; 414 fHandlerToken = from.fHandlerToken; 415 fTeam = from.fTeam; 416 } 417 return *this; 418 } 419 420 421 /*! \brief Returns whether this and the supplied messenger have the same 422 target. 423 424 \param other The other messenger. 425 \return \c true, if the messengers have the same target or if both aren't 426 properly initialzed, \c false otherwise. 427 */ 428 bool 429 BMessenger::operator==(const BMessenger &other) const 430 { 431 // Note: The fTeam fields are not compared. 432 return fPort == other.fPort 433 && fHandlerToken == other.fHandlerToken; 434 } 435 436 437 /*! \brief Returns whether the messenger's target looper does still exist. 438 439 It is not checked whether the target handler is also still existing. 440 441 \return \c true, if the messenger's target looper does still exist, 442 \c false otherwise. 443 */ 444 bool 445 BMessenger::IsValid() const 446 { 447 port_info info; 448 return fPort >= 0 && get_port_info(fPort, &info) == B_OK; 449 } 450 451 452 /*! \brief Returns the ID of the team the messenger's target lives in. 453 454 \return The team of the messenger's target. 455 */ 456 team_id 457 BMessenger::Team() const 458 { 459 return fTeam; 460 } 461 462 463 // #pragma mark - Private or reserved 464 465 466 /*! \brief Sets the messenger's team, target looper port and handler token. 467 468 To target the preferred handler, use B_PREFERRED_TOKEN as token. 469 470 \param team The target's team. 471 \param port The target looper port. 472 \param token The target handler token. 473 */ 474 void 475 BMessenger::_SetTo(team_id team, port_id port, int32 token) 476 { 477 fTeam = team; 478 fPort = port; 479 fHandlerToken = token; 480 } 481 482 483 /*! \brief Initializes the BMessenger object's data given the signature and/or 484 team ID of a target. 485 486 When only a signature is given, and multiple instances of the application 487 are running it is undeterminate which one is chosen as the target. In case 488 only a team ID is passed, the target application is identified uniquely. 489 If both are supplied, the application identified by the team ID must have 490 a matching signature, otherwise the initilization fails. 491 492 \param signature The target application's signature. May be \c NULL. 493 \param team The target application's team ID. May be < 0. 494 \param result An optional pointer to a pre-allocated status_t into which 495 the result of the initialization is written. 496 */ 497 void 498 BMessenger::_InitData(const char* signature, team_id team, status_t* _result) 499 { 500 status_t error = B_OK; 501 // get an app_info 502 app_info info; 503 if (team < 0) { 504 // no team ID given 505 if (signature) { 506 error = be_roster->GetAppInfo(signature, &info); 507 team = info.team; 508 // B_ERROR means that no application with the given signature 509 // is running. But we are supposed to return B_BAD_VALUE. 510 if (error == B_ERROR) 511 error = B_BAD_VALUE; 512 } else 513 error = B_BAD_TYPE; 514 } else { 515 // a team ID is given 516 error = be_roster->GetRunningAppInfo(team, &info); 517 // Compare the returned signature with the supplied one. 518 if (error == B_OK && signature && strcasecmp(signature, info.signature)) 519 error = B_MISMATCHED_VALUES; 520 } 521 // check whether the app flags say B_ARGV_ONLY 522 if (error == B_OK && (info.flags & B_ARGV_ONLY)) { 523 error = B_BAD_TYPE; 524 // Set the team ID nevertheless -- that's what Be's implementation 525 // does. Don't know, if that is a bug, but at least it doesn't harm. 526 fTeam = team; 527 } 528 // init our members 529 if (error == B_OK) { 530 fTeam = team; 531 fPort = info.port; 532 fHandlerToken = B_PREFERRED_TOKEN; 533 } 534 535 // return the error 536 if (_result) 537 *_result = error; 538 } 539 540 541 /*! \brief Returns whether the first one of two BMessengers is less than the 542 second one. 543 544 This method defines an order on BMessengers based on their member 545 variables \c fPort, \c fHandlerToken and \c fPreferredTarget. 546 547 \param a The first messenger. 548 \param b The second messenger. 549 \return \c true, if \a a is less than \a b, \c false otherwise. 550 */ 551 bool 552 operator<(const BMessenger &_a, const BMessenger &_b) 553 { 554 BMessenger::Private a(const_cast<BMessenger&>(_a)); 555 BMessenger::Private b(const_cast<BMessenger&>(_b)); 556 557 // significance: 558 // 1. fPort 559 // 2. fHandlerToken 560 // 3. fPreferredTarget 561 // fTeam is insignificant 562 return (a.Port() < b.Port() 563 || a.Port() == b.Port() 564 && (a.Token() < b.Token() 565 || a.Token() == b.Token() 566 && !a.IsPreferredTarget() 567 && b.IsPreferredTarget())); 568 } 569 570 571 /*! \brief Returns whether two BMessengers have not the same target. 572 573 \param a The first messenger. 574 \param b The second messenger. 575 \return \c false, if \a a and \a b have the same targets or are both not 576 properly initialized, \c true otherwise. 577 */ 578 bool 579 operator!=(const BMessenger &a, const BMessenger &b) 580 { 581 return !(a == b); 582 } 583 584