2 * Copyright 2001-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Ingo Weinhold (bonefish@users.sf.net)
10 #include <Messenger.h>
16 #include <Application.h>
17 #include <AutoLocker.h>
25 #include <LaunchRoster.h>
26 #include <LooperList.h>
27 #include <MessagePrivate.h>
28 #include <MessageUtils.h>
29 #include <TokenSpace.h>
37 using BPrivate::gDefaultTokens
;
38 using BPrivate::gLooperList
;
39 using BPrivate::BLooperList
;
42 NOT_IMPLEMENTED
= B_ERROR
,
46 BMessenger::BMessenger()
49 fHandlerToken(B_NULL_TOKEN
),
55 BMessenger::BMessenger(const char* signature
, team_id team
, status_t
* result
)
58 fHandlerToken(B_NULL_TOKEN
),
61 _InitData(signature
, team
, result
);
65 BMessenger::BMessenger(const BHandler
* handler
, const BLooper
* looper
,
69 fHandlerToken(B_NULL_TOKEN
),
72 _InitData(handler
, looper
, _result
);
76 BMessenger::BMessenger(const BMessenger
& other
)
79 fHandlerToken(other
.fHandlerToken
),
85 BMessenger::~BMessenger()
90 // #pragma mark - Target
94 BMessenger::IsTargetLocal() const
96 return BPrivate::current_team() == fTeam
;
101 BMessenger::Target(BLooper
** _looper
) const
103 BHandler
* handler
= NULL
;
105 && (fHandlerToken
> B_NULL_TOKEN
106 || fHandlerToken
== B_PREFERRED_TOKEN
)) {
107 gDefaultTokens
.GetToken(fHandlerToken
, B_HANDLER_TOKEN
,
110 *_looper
= BPrivate::gLooperList
.LooperForPort(fPort
);
119 BMessenger::LockTarget() const
121 BLooper
* looper
= NULL
;
123 if (looper
!= NULL
&& looper
->Lock()) {
124 if (looper
->fMsgPort
== fPort
)
136 BMessenger::LockTargetWithTimeout(bigtime_t timeout
) const
138 BLooper
* looper
= NULL
;
143 status_t result
= looper
->LockWithTimeout(timeout
);
145 if (result
== B_OK
&& looper
->fMsgPort
!= fPort
) {
147 return B_BAD_PORT_ID
;
154 // #pragma mark - Message sending
158 BMessenger::SendMessage(uint32 command
, BHandler
* replyTo
) const
160 BMessage
message(command
);
161 return SendMessage(&message
, replyTo
);
166 BMessenger::SendMessage(BMessage
* message
, BHandler
* replyTo
,
167 bigtime_t timeout
) const
169 DBG(OUT("BMessenger::SendMessage2(%.4s)\n", (char*)&message
->what
));
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
);
177 DBG(OUT("BMessenger::SendMessage2() done: %lx\n", result
));
184 BMessenger::SendMessage(BMessage
* message
, BMessenger replyTo
,
185 bigtime_t timeout
) const
190 return BMessage::Private(message
).SendMessage(fPort
, fTeam
, fHandlerToken
,
191 timeout
, false, replyTo
);
196 BMessenger::SendMessage(uint32 command
, BMessage
* reply
) const
198 BMessage
message(command
);
200 return SendMessage(&message
, reply
);
205 BMessenger::SendMessage(BMessage
* message
, BMessage
* reply
,
206 bigtime_t deliveryTimeout
, bigtime_t replyTimeout
) const
208 if (message
== NULL
|| reply
== NULL
)
211 status_t result
= BMessage::Private(message
).SendMessage(fPort
, fTeam
,
212 fHandlerToken
, reply
, deliveryTimeout
, replyTimeout
);
214 // map this result for now
215 if (result
== B_BAD_TEAM_ID
)
216 result
= B_BAD_PORT_ID
;
222 // #pragma mark - Operators and misc
226 BMessenger::SetTo(const char* signature
, team_id team
)
228 status_t result
= B_OK
;
229 _InitData(signature
, team
, &result
);
236 BMessenger::SetTo(const BHandler
* handler
, const BLooper
* looper
)
238 status_t result
= B_OK
;
239 _InitData(handler
, looper
, &result
);
246 BMessenger::operator=(const BMessenger
& other
)
248 if (this != &other
) {
250 fHandlerToken
= other
.fHandlerToken
;
259 BMessenger::operator==(const BMessenger
& other
) const
261 // Note: The fTeam fields are not compared.
262 return fPort
== other
.fPort
&& fHandlerToken
== other
.fHandlerToken
;
267 BMessenger::IsValid() const
270 return fPort
>= 0 && get_port_info(fPort
, &info
) == B_OK
;
275 BMessenger::Team() const
282 BMessenger::HashValue() const
284 return fPort
* 19 + fHandlerToken
;
288 // #pragma mark - Private or reserved
291 /*! Sets the messenger's team, target looper port and handler token.
293 To target the preferred handler, use \c B_PREFERRED_TOKEN as token.
295 \param team The target's team.
296 \param port The target looper port.
297 \param token The target handler token.
300 BMessenger::_SetTo(team_id team
, port_id port
, int32 token
)
304 fHandlerToken
= token
;
308 /*! Initializes the BMessenger object's data given the signature and/or
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.
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.
323 BMessenger::_InitData(const char* signature
, team_id team
, status_t
* _result
)
325 status_t result
= B_OK
;
331 if (signature
!= NULL
) {
332 // Try existing launch communication data first
334 if (BLaunchRoster().GetData(signature
, data
) == B_OK
) {
335 info
.port
= data
.GetInt32("port", -1);
336 team
= data
.GetInt32("team", -5);
339 result
= be_roster
->GetAppInfo(signature
, &info
);
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
;
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
;
358 // check whether the app flags say B_ARGV_ONLY
359 if (result
== B_OK
&& (info
.flags
& B_ARGV_ONLY
) != 0) {
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.
366 if (result
== B_OK
) {
369 fHandlerToken
= B_PREFERRED_TOKEN
;
378 /*! Initializes the BMessenger to target the local BHandler and/or BLooper.
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
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.
392 BMessenger::_InitData(const BHandler
* handler
, const BLooper
* looper
,
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
;
403 looper
= handler
->Looper();
405 result
= B_MISMATCHED_VALUES
;
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
)
417 fTeam
= looper
->Team();
419 result
= B_BAD_VALUE
;
428 // #pragma mark - Operator functions
432 operator<(const BMessenger
& _a
, const BMessenger
& _b
)
434 BMessenger::Private
a(const_cast<BMessenger
&>(_a
));
435 BMessenger::Private
b(const_cast<BMessenger
&>(_b
));
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()))));
452 operator!=(const BMessenger
& a
, const BMessenger
& b
)