1 /* 2 * Copyright 2001-2015 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold (bonefish@users.sf.net) 7 */ 8 9 10 #include <Messenger.h> 11 12 #include <new> 13 #include <stdio.h> 14 #include <strings.h> 15 16 #include <Application.h> 17 #include <AutoLocker.h> 18 #include <Handler.h> 19 #include <Looper.h> 20 #include <Message.h> 21 #include <OS.h> 22 #include <Roster.h> 23 24 #include <AppMisc.h> 25 #include <LaunchRoster.h> 26 #include <LooperList.h> 27 #include <MessagePrivate.h> 28 #include <MessageUtils.h> 29 #include <TokenSpace.h> 30 31 32 // debugging 33 //#define DBG(x) x 34 #define DBG(x) 35 #define OUT printf 36 37 using BPrivate::gDefaultTokens; 38 using BPrivate::gLooperList; 39 using BPrivate::BLooperList; 40 41 42 BMessenger::BMessenger() 43 : 44 fPort(-1), 45 fHandlerToken(B_NULL_TOKEN), 46 fTeam(-1) 47 { 48 } 49 50 51 BMessenger::BMessenger(const char* signature, team_id team, status_t* result) 52 : 53 fPort(-1), 54 fHandlerToken(B_NULL_TOKEN), 55 fTeam(-1) 56 { 57 _InitData(signature, team, result); 58 } 59 60 61 BMessenger::BMessenger(const BHandler* handler, const BLooper* looper, 62 status_t* _result) 63 : 64 fPort(-1), 65 fHandlerToken(B_NULL_TOKEN), 66 fTeam(-1) 67 { 68 _InitData(handler, looper, _result); 69 } 70 71 72 BMessenger::BMessenger(const BMessenger& other) 73 : 74 fPort(other.fPort), 75 fHandlerToken(other.fHandlerToken), 76 fTeam(other.fTeam) 77 { 78 } 79 80 81 BMessenger::~BMessenger() 82 { 83 } 84 85 86 // #pragma mark - Target 87 88 89 bool 90 BMessenger::IsTargetLocal() const 91 { 92 return BPrivate::current_team() == fTeam; 93 } 94 95 96 BHandler* 97 BMessenger::Target(BLooper** _looper) const 98 { 99 BHandler* handler = NULL; 100 if (IsTargetLocal() 101 && (fHandlerToken > B_NULL_TOKEN 102 || fHandlerToken == B_PREFERRED_TOKEN)) { 103 gDefaultTokens.GetToken(fHandlerToken, B_HANDLER_TOKEN, 104 (void**)&handler); 105 if (_looper) 106 *_looper = BPrivate::gLooperList.LooperForPort(fPort); 107 } else if (_looper) 108 *_looper = NULL; 109 110 return handler; 111 } 112 113 114 bool 115 BMessenger::LockTarget() const 116 { 117 BLooper* looper = NULL; 118 Target(&looper); 119 if (looper != NULL && looper->Lock()) { 120 if (looper->fMsgPort == fPort) 121 return true; 122 123 looper->Unlock(); 124 return false; 125 } 126 127 return false; 128 } 129 130 131 status_t 132 BMessenger::LockTargetWithTimeout(bigtime_t timeout) const 133 { 134 BLooper* looper = NULL; 135 Target(&looper); 136 if (looper == NULL) 137 return B_BAD_VALUE; 138 139 status_t result = looper->LockWithTimeout(timeout); 140 141 if (result == B_OK && looper->fMsgPort != fPort) { 142 looper->Unlock(); 143 return B_BAD_PORT_ID; 144 } 145 146 return result; 147 } 148 149 150 // #pragma mark - Message sending 151 152 153 status_t 154 BMessenger::SendMessage(uint32 command, BHandler* replyTo) const 155 { 156 BMessage message(command); 157 return SendMessage(&message, replyTo); 158 } 159 160 161 status_t 162 BMessenger::SendMessage(BMessage* message, BHandler* replyTo, 163 bigtime_t timeout) const 164 { 165 DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message->what)); 166 167 status_t result = message != NULL ? B_OK : B_BAD_VALUE; 168 if (result == B_OK) { 169 BMessenger replyMessenger(replyTo); 170 result = SendMessage(message, replyMessenger, timeout); 171 } 172 173 DBG(OUT("BMessenger::SendMessage2() done: %lx\n", result)); 174 175 return result; 176 } 177 178 179 status_t 180 BMessenger::SendMessage(BMessage* message, BMessenger replyTo, 181 bigtime_t timeout) const 182 { 183 if (message == NULL) 184 return B_BAD_VALUE; 185 186 return BMessage::Private(message).SendMessage(fPort, fTeam, fHandlerToken, 187 timeout, false, replyTo); 188 } 189 190 191 status_t 192 BMessenger::SendMessage(uint32 command, BMessage* reply) const 193 { 194 BMessage message(command); 195 196 return SendMessage(&message, reply); 197 } 198 199 200 status_t 201 BMessenger::SendMessage(BMessage* message, BMessage* reply, 202 bigtime_t deliveryTimeout, bigtime_t replyTimeout) const 203 { 204 if (message == NULL || reply == NULL) 205 return B_BAD_VALUE; 206 207 status_t result = BMessage::Private(message).SendMessage(fPort, fTeam, 208 fHandlerToken, reply, deliveryTimeout, replyTimeout); 209 210 // map this result for now 211 if (result == B_BAD_TEAM_ID) 212 result = B_BAD_PORT_ID; 213 214 return result; 215 } 216 217 218 // #pragma mark - Operators and misc 219 220 221 status_t 222 BMessenger::SetTo(const char* signature, team_id team) 223 { 224 status_t result = B_OK; 225 _InitData(signature, team, &result); 226 227 return result; 228 } 229 230 231 status_t 232 BMessenger::SetTo(const BHandler* handler, const BLooper* looper) 233 { 234 status_t result = B_OK; 235 _InitData(handler, looper, &result); 236 237 return result; 238 } 239 240 241 BMessenger& 242 BMessenger::operator=(const BMessenger& other) 243 { 244 if (this != &other) { 245 fPort = other.fPort; 246 fHandlerToken = other.fHandlerToken; 247 fTeam = other.fTeam; 248 } 249 250 return *this; 251 } 252 253 254 bool 255 BMessenger::operator==(const BMessenger& other) const 256 { 257 // Note: The fTeam fields are not compared. 258 return fPort == other.fPort && fHandlerToken == other.fHandlerToken; 259 } 260 261 262 bool 263 BMessenger::IsValid() const 264 { 265 port_info info; 266 return fPort >= 0 && get_port_info(fPort, &info) == B_OK; 267 } 268 269 270 team_id 271 BMessenger::Team() const 272 { 273 return fTeam; 274 } 275 276 277 uint32 278 BMessenger::HashValue() const 279 { 280 return fPort * 19 + fHandlerToken; 281 } 282 283 284 // #pragma mark - Private or reserved 285 286 287 /*! Sets the messenger's team, target looper port and handler token. 288 289 To target the preferred handler, use \c B_PREFERRED_TOKEN as token. 290 291 \param team The target's team. 292 \param port The target looper port. 293 \param token The target handler token. 294 */ 295 void 296 BMessenger::_SetTo(team_id team, port_id port, int32 token) 297 { 298 fTeam = team; 299 fPort = port; 300 fHandlerToken = token; 301 } 302 303 304 /*! Initializes the BMessenger object's data given the signature and/or 305 team ID of a target. 306 307 When only a signature is given, and multiple instances of the application 308 are running it is undeterminate which one is chosen as the target. In case 309 only a team ID is passed, the target application is identified uniquely. 310 If both are supplied, the application identified by the team ID must have 311 a matching signature, otherwise the initilization fails. 312 313 \param signature The target application's signature. May be \c NULL. 314 \param team The target application's team ID. May be < 0. 315 \param result An optional pointer to a pre-allocated status_t into which 316 the result of the initialization is written. 317 */ 318 void 319 BMessenger::_InitData(const char* signature, team_id team, status_t* _result) 320 { 321 status_t result = B_OK; 322 323 // get an app_info 324 app_info info; 325 if (team < 0) { 326 // no team ID given 327 if (signature != NULL) { 328 // Try existing launch communication data first 329 BMessage data; 330 if (BLaunchRoster().GetData(signature, data) == B_OK) { 331 info.port = data.GetInt32("port", -1); 332 team = data.GetInt32("team", -5); 333 } 334 if (info.port < 0) { 335 result = be_roster->GetAppInfo(signature, &info); 336 team = info.team; 337 // B_ERROR means that no application with the given signature 338 // is running. But we are supposed to return B_BAD_VALUE. 339 if (result == B_ERROR) 340 result = B_BAD_VALUE; 341 } else 342 info.flags = 0; 343 } else 344 result = B_BAD_TYPE; 345 } else { 346 // a team ID is given 347 result = be_roster->GetRunningAppInfo(team, &info); 348 // Compare the returned signature with the supplied one. 349 if (result == B_OK && signature != NULL 350 && strcasecmp(signature, info.signature) != 0) { 351 result = B_MISMATCHED_VALUES; 352 } 353 } 354 // check whether the app flags say B_ARGV_ONLY 355 if (result == B_OK && (info.flags & B_ARGV_ONLY) != 0) { 356 result = B_BAD_TYPE; 357 // Set the team ID nevertheless -- that's what Be's implementation 358 // does. Don't know, if that is a bug, but at least it doesn't harm. 359 fTeam = team; 360 } 361 // init our members 362 if (result == B_OK) { 363 fTeam = team; 364 fPort = info.port; 365 fHandlerToken = B_PREFERRED_TOKEN; 366 } 367 368 // return the result 369 if (_result != NULL) 370 *_result = result; 371 } 372 373 374 /*! Initializes the BMessenger to target the local BHandler and/or BLooper. 375 376 When a \c NULL handler is supplied, the preferred handler in the given 377 looper is targeted. If no looper is supplied the looper the given handler 378 belongs to is used -- that means in particular, that the handler must 379 already belong to a looper. If both are supplied the handler must actually 380 belong to looper. 381 382 \param handler The target handler. May be \c NULL. 383 \param looper The target looper. May be \c NULL. 384 \param result An optional pointer to a pre-allocated status_t into which 385 the result of the initialization is written. 386 */ 387 void 388 BMessenger::_InitData(const BHandler* handler, const BLooper* looper, 389 status_t* _result) 390 { 391 status_t result = (handler != NULL || looper != NULL) ? B_OK : B_BAD_VALUE; 392 if (result == B_OK) { 393 if (handler != NULL) { 394 // BHandler is given, check/retrieve the looper. 395 if (looper != NULL) { 396 if (handler->Looper() != looper) 397 result = B_MISMATCHED_VALUES; 398 } else { 399 looper = handler->Looper(); 400 if (looper == NULL) 401 result = B_MISMATCHED_VALUES; 402 } 403 } 404 405 // set port, token,... 406 if (result == B_OK) { 407 AutoLocker<BLooperList> locker(gLooperList); 408 if (locker.IsLocked() && gLooperList.IsLooperValid(looper)) { 409 fPort = looper->fMsgPort; 410 fHandlerToken = handler != NULL 411 ? _get_object_token_(handler) 412 : B_PREFERRED_TOKEN; 413 fTeam = looper->Team(); 414 } else 415 result = B_BAD_VALUE; 416 } 417 } 418 419 if (_result != NULL) 420 *_result = result; 421 } 422 423 424 // #pragma mark - Operator functions 425 426 427 bool 428 operator<(const BMessenger& _a, const BMessenger& _b) 429 { 430 BMessenger::Private a(const_cast<BMessenger&>(_a)); 431 BMessenger::Private b(const_cast<BMessenger&>(_b)); 432 433 // significance: 434 // 1. fPort 435 // 2. fHandlerToken 436 // 3. fPreferredTarget 437 // fTeam is insignificant 438 return (a.Port() < b.Port() 439 || (a.Port() == b.Port() 440 && (a.Token() < b.Token() 441 || (a.Token() == b.Token() 442 && !a.IsPreferredTarget() 443 && b.IsPreferredTarget())))); 444 } 445 446 447 bool 448 operator!=(const BMessenger& a, const BMessenger& b) 449 { 450 return !(a == b); 451 } 452