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