Skip to content

Commit

Permalink
BMessage: implemented KMessage reply.
Browse files Browse the repository at this point in the history
* When you receive a message from a KMessage, and reply to it,
  it will automatically reply as KMessage, too.
* This allows to communicate with BLoopers from within the kernel
  or libroot.so.
  • Loading branch information
axeld committed May 13, 2015
1 parent 446d4dc commit 5ce80a7
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 10 deletions.
6 changes: 4 additions & 2 deletions headers/build/private/app/MessagePrivate.h
@@ -1,5 +1,5 @@
/*
* Copyright 2005-2009, Haiku Inc. All rights reserved.
* Copyright 2005-2015, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
Expand All @@ -8,6 +8,7 @@
#ifndef _MESSAGE_PRIVATE_H_
#define _MESSAGE_PRIVATE_H_


#include <Message.h>
#include <Messenger.h>
#include <MessengerPrivate.h>
Expand All @@ -30,7 +31,8 @@ enum {
MESSAGE_FLAG_WAS_DELIVERED = 0x0010,
MESSAGE_FLAG_HAS_SPECIFIERS = 0x0020,
MESSAGE_FLAG_WAS_DROPPED = 0x0040,
MESSAGE_FLAG_PASS_BY_AREA = 0x0080
MESSAGE_FLAG_PASS_BY_AREA = 0x0080,
MESSAGE_FLAG_REPLY_AS_KMESSAGE = 0x0100
};


Expand Down
3 changes: 3 additions & 0 deletions headers/private/app/MessageAdapter.h
Expand Up @@ -40,6 +40,9 @@ class MessageAdapter {
static status_t Unflatten(uint32 format, BMessage* into,
BDataIO* stream);

static status_t ConvertToKMessage(const BMessage* from,
KMessage& to);

private:
static status_t _ConvertFromKMessage(const KMessage* from,
BMessage* to);
Expand Down
6 changes: 4 additions & 2 deletions headers/private/app/MessagePrivate.h
@@ -1,5 +1,5 @@
/*
* Copyright 2005-2010, Haiku Inc. All rights reserved.
* Copyright 2005-2015, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
Expand All @@ -8,6 +8,7 @@
#ifndef _MESSAGE_PRIVATE_H_
#define _MESSAGE_PRIVATE_H_


#include <Message.h>
#include <Messenger.h>
#include <MessengerPrivate.h>
Expand All @@ -30,7 +31,8 @@ enum {
MESSAGE_FLAG_WAS_DELIVERED = 0x0010,
MESSAGE_FLAG_HAS_SPECIFIERS = 0x0020,
MESSAGE_FLAG_WAS_DROPPED = 0x0040,
MESSAGE_FLAG_PASS_BY_AREA = 0x0080
MESSAGE_FLAG_PASS_BY_AREA = 0x0080,
MESSAGE_FLAG_REPLY_AS_KMESSAGE = 0x0100
};


Expand Down
18 changes: 13 additions & 5 deletions src/kits/app/Message.cpp
Expand Up @@ -913,6 +913,8 @@ BMessage::SendReply(BMessage* reply, BMessenger replyTo, bigtime_t timeout)
BMessenger::Private messengerPrivate(messenger);
messengerPrivate.SetTo(fHeader->reply_team, fHeader->reply_port,
fHeader->reply_target);
if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0)
reply->fHeader->flags |= MESSAGE_FLAG_REPLY_AS_KMESSAGE;

if ((fHeader->flags & MESSAGE_FLAG_REPLY_REQUIRED) != 0) {
if ((fHeader->flags & MESSAGE_FLAG_REPLY_DONE) != 0)
Expand All @@ -923,11 +925,9 @@ BMessage::SendReply(BMessage* reply, BMessenger replyTo, bigtime_t timeout)
status_t result = messenger.SendMessage(reply, replyTo, timeout);
reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;

if (result != B_OK) {
if (set_port_owner(messengerPrivate.Port(),
if (result != B_OK && set_port_owner(messengerPrivate.Port(),
messengerPrivate.Team()) == B_BAD_TEAM_ID) {
delete_port(messengerPrivate.Port());
}
delete_port(messengerPrivate.Port());
}

return result;
Expand Down Expand Up @@ -993,7 +993,8 @@ BMessage::SendReply(BMessage* reply, BMessage* replyToReply,
return B_BAD_REPLY;

reply->AddMessage("_previous_", this);
reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY;
reply->fHeader->flags |= MESSAGE_FLAG_IS_REPLY
| (fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE);
status_t result = messenger.SendMessage(reply, replyToReply, sendTimeout,
replyTimeout);
reply->fHeader->flags &= ~MESSAGE_FLAG_IS_REPLY;
Expand Down Expand Up @@ -2164,6 +2165,13 @@ BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
header->message_area = transfered;
}
#endif
} else if ((fHeader->flags & MESSAGE_FLAG_REPLY_AS_KMESSAGE) != 0) {
KMessage toMessage;
result = BPrivate::MessageAdapter::ConvertToKMessage(this, toMessage);
if (result != B_OK)
return result;

return toMessage.SendTo(port, token);
} else {
size = FlattenedSize();
buffer = (char*)malloc(size);
Expand Down
46 changes: 45 additions & 1 deletion src/kits/app/MessageAdapter.cpp
@@ -1,11 +1,13 @@
/*
* Copyright 2005-2007, Haiku Inc. All rights reserved.
* Copyright 2005-2015, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Michael Lotz <mmlr@mlotz.ch>
*/


#include <MessageAdapter.h>
#include <MessagePrivate.h>
#include <MessageUtils.h>
Expand Down Expand Up @@ -237,6 +239,44 @@ MessageAdapter::Unflatten(uint32 format, BMessage *into, BDataIO *stream)
}


/*static*/ status_t
MessageAdapter::ConvertToKMessage(const BMessage* from, KMessage& to)
{
if (from == NULL)
return B_BAD_VALUE;

BMessage::Private fromPrivate(const_cast<BMessage*>(from));
BMessage::message_header* header = fromPrivate.GetMessageHeader();
uint8* data = fromPrivate.GetMessageData();

// Iterate through the fields and import them in the target message
BMessage::field_header* field = fromPrivate.GetMessageFields();
for (uint32 i = 0; i < header->field_count; i++, field++) {
const char* name = (const char*)data + field->offset;
const uint8* fieldData = data + field->offset + field->name_length;
bool fixedSize = (field->flags & FIELD_FLAG_FIXED_SIZE) != 0;

if (fixedSize) {
status_t status = to.AddArray(name, field->type, fieldData,
field->data_size / field->count, field->count);
if (status != B_OK)
return status;
} else {
for (uint32 i = 0; i < field->count; i++) {
uint32 itemSize = *(uint32*)fieldData;
fieldData += sizeof(uint32);
status_t status = to.AddData(name, field->type, fieldData,
itemSize, false);
if (status != B_OK)
return status;
fieldData += itemSize;
}
}
}
return B_OK;
}


/*static*/ status_t
MessageAdapter::_ConvertFromKMessage(const KMessage *fromMessage,
BMessage *toMessage)
Expand All @@ -252,6 +292,10 @@ MessageAdapter::_ConvertFromKMessage(const KMessage *fromMessage,
toPrivate.SetTarget(fromMessage->TargetToken());
toPrivate.SetReply(B_SYSTEM_TEAM, fromMessage->ReplyPort(),
fromMessage->ReplyToken());
if (fromMessage->ReplyPort() >= 0) {
toPrivate.GetMessageHeader()->flags |= MESSAGE_FLAG_REPLY_AS_KMESSAGE
| MESSAGE_FLAG_REPLY_REQUIRED;
}

// Iterate through the fields and import them in the target message
KMessageField field;
Expand Down

0 comments on commit 5ce80a7

Please sign in to comment.