As this remote messaging framework tries to be as transparent as possible, the API footprint is accordingly small:
For sending messages to an application on a remote host, all that is needed, is a BMessenger
targeting that application. Having one, the communication works pretty much as between local applications.
const char* appSignature = "application/x-vnd.me.my-app"; RemoteRoster roster; BMessenger messenger; if (roster.SetTo("remote.host.com") == B_OK && roster.GetMessenger(appSignature, &messenger) == B_OK) { messenger.SendMessage(...); }
For the remote application it will be completely transparent, whether the message it receives comes from another machine or not. If it sends a reply, that message will arrive at the correct destination.
Synchronous messaging works properly as well, and is, for some reasons, even encouraged.
Although the framework tries to be as transparent as possible, it isn't entirely. To understand in which cases and why it is not, it is important to understand the inner workings a bit.
As used in the example the standard way to get a BMessenger
targeting a remote application is via RemoteRoster::GetMessenger(). The method sends the request to the RMessageServer, which in turn forwards it to the RMessageServer on the remote host. That will get the messenger (if possible) and return it to the local server. Naturally the messenger is not valid on this machine (or has a completely different target), so the server must translate it.
Therefore it creates a dedicated BHandler that serves as a proxy for the remote target. A messenger to that handler is passed back as a reply to the original request and is returned by RemoteRoster::GetMessenger(). When the application sends a message via that messenger, it is sent to the proxy handler, which, knowing the actual target, sends it to the respective remote RMessageServer, that delivers the message.
The last part is not as straight forward as it sounds, though. The remote server first has a closer look at the message and finds all messengers it contains, translating them the in the same way, just described, by creating respective proxy handlers. Afterwards, the message is sent synchronously to the target. This is necessary to get the reply the target will send, respectively know that it doesn't send a reply (B_NO_REPLY)
.
The reply is sent back the same way the original message was sent (just the other way around, of course) -- messenger translation, synchronous delivery... The ping-ponging of replies ends as soon as a B_NO_REPLY
is sent or the message delivery failed for some reason. If it fails, e.g. because the target does not longer exist, an RMESSAGE_DELIVERY_FAILED message is sent as a reply. If the delivery times out RMESSAGE_DELIVERY_TIMED_OUT is sent instead.
There are some behavioral anomalies:
BMessenger::SendMessage()
returns B_OK
, the caller can be sure that the message arrived at the destination. That is not so for remote messages. In this case the result only says that the message arrived at the RMessageServer. The message delivery might still fail. A RMESSAGE_DELIVERY_FAILED
or RMESSAGE_DELIVERY_TIMED_OUT
will be sent as a reply in those cases. For that reason it is encouraged to use synchronous messaging and check for these error replies.true
when asking BMessage::IsSourceWaiting()
on the delivered message. Furthermore BMessage::ReturnAddress()
will return a messenger that is only temporarily valid. When using asynchronous messaging locally, the BMessage::ReturnAddress()
will refer to the handler/looper the caller supplied to BMessenger::SendMessage()
. Another reason to prefer synchronous messaging when sending remote messages.
The RMessageServer application implements the suite "suite/vnd.bonefish.rmessage_server
".
Command | Specifier | Meaning |
B_GET_PROPERTY | B_DIRECT_SPECIFIER | Returns the addresses of all currently connected hosts as B_STRING_TYPE[] . |
n/a | B_NAME_SPECIFIER | The message is forwarded to the host with the given name. |
The property "Host" implements the suite "suite/vnd.bonefish.rmessage_host
".
Property "Host"::"Application"
Command | Specifier | Meaning |
B_GET_PROPERTY | B_DIRECT_SPECIFIER | Returns the signatures of all applications running on the host as B_STRING_TYPE[] . |
n/a | B_NAME_SPECIFIER | The message is forwarded to the application with the given signature/name. |
Command | Specifier | Meaning |
B_GET_PROPERTY | B_DIRECT_SPECIFIER | Returns the suites implemented by the "Host " property. |