From 5ce80a78c976c96d3afe4e9bd9eb473cb54c362c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 21 Apr 2015 18:52:13 +0200 Subject: [PATCH] BMessage: implemented KMessage reply. * 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. --- headers/build/private/app/MessagePrivate.h | 6 ++- headers/private/app/MessageAdapter.h | 3 ++ headers/private/app/MessagePrivate.h | 6 ++- src/kits/app/Message.cpp | 18 ++++++--- src/kits/app/MessageAdapter.cpp | 46 +++++++++++++++++++++- 5 files changed, 69 insertions(+), 10 deletions(-) diff --git a/headers/build/private/app/MessagePrivate.h b/headers/build/private/app/MessagePrivate.h index 7fe12277287..e634dd89ab4 100644 --- a/headers/build/private/app/MessagePrivate.h +++ b/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: @@ -8,6 +8,7 @@ #ifndef _MESSAGE_PRIVATE_H_ #define _MESSAGE_PRIVATE_H_ + #include #include #include @@ -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 }; diff --git a/headers/private/app/MessageAdapter.h b/headers/private/app/MessageAdapter.h index e62e08a362d..c3200787f7f 100644 --- a/headers/private/app/MessageAdapter.h +++ b/headers/private/app/MessageAdapter.h @@ -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); diff --git a/headers/private/app/MessagePrivate.h b/headers/private/app/MessagePrivate.h index dc749a0f410..9e6a6117b3b 100644 --- a/headers/private/app/MessagePrivate.h +++ b/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: @@ -8,6 +8,7 @@ #ifndef _MESSAGE_PRIVATE_H_ #define _MESSAGE_PRIVATE_H_ + #include #include #include @@ -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 }; diff --git a/src/kits/app/Message.cpp b/src/kits/app/Message.cpp index f1a47034cdd..6ece8943c86 100644 --- a/src/kits/app/Message.cpp +++ b/src/kits/app/Message.cpp @@ -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) @@ -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; @@ -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; @@ -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); diff --git a/src/kits/app/MessageAdapter.cpp b/src/kits/app/MessageAdapter.cpp index 8e115695bcd..317d0e9dbce 100644 --- a/src/kits/app/MessageAdapter.cpp +++ b/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 */ + + #include #include #include @@ -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(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) @@ -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;