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