Moved the functionality to flatten and unflatten a BMessage header into

a separate class. This allowed to improve _SendFlattenedMessage() to
deal properly with flattened BMessages as well.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11116 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2005-01-29 00:19:50 +00:00
parent b9717a7150
commit efbea3a07a
2 changed files with 396 additions and 257 deletions

View File

@ -295,10 +295,12 @@ virtual ~BMessage();
class Private;
private:
class Header;
friend class BMessageQueue;
friend class BMessenger;
friend class BApplication;
friend class Header;
friend class Private;
friend inline void _set_message_target_(BMessage *, int32, bool);
@ -314,8 +316,6 @@ virtual void _ReservedMessage2();
virtual void _ReservedMessage3();
void init_data();
status_t flatten_hdr(BDataIO *stream) const;
status_t unflatten_hdr(BDataIO *stream, bool& swap);
status_t flatten_target_info(BDataIO *stream,
ssize_t size,
uchar flags) const;
@ -331,7 +331,6 @@ virtual void _ReservedMessage3();
ssize_t calc_size(uchar flags) const;
ssize_t calc_hdr_size(uchar flags) const;
ssize_t min_hdr_size() const;
status_t nfind_data( const char *name,
type_code type,
int32 index,

View File

@ -101,6 +101,345 @@ static status_t handle_reply(port_id reply_port,
static status_t convert_message(const KMessage *fromMessage,
BMessage *toMessage);
static ssize_t min_hdr_size();
// #pragma mark -
class BMessage::Header {
public:
Header() {}
Header(const BMessage &message) { ReadFrom(message); }
status_t ReadFrom(BDataIO &stream);
void ReadFrom(const BMessage &message);
status_t WriteTo(BDataIO &stream);
void WriteTo(BMessage &message);
uint32 CalculateCheckSum() const;
uint32 CalculateHeaderSize() const;
bool IsSwapped() const { return fSwapped; }
bool HasTarget() const { return (fFlags & MSG_FLAG_INCL_TARGET); }
void SetTarget(int32 token, bool preferred);
private:
int32 fMagic;
int32 fBodySize;
uint32 fWhat;
uint8 fFlags;
int32 fTargetToken;
port_id fReplyPort;
int32 fReplyToken;
team_id fReplyTeam;
bool fPreferredTarget;
bool fReplyRequired;
bool fReplyDone;
bool fIsReply;
bool fSwapped;
};
// ReadFrom
status_t
BMessage::Header::ReadFrom(BDataIO &stream)
{
int32 checkSum;
uchar csBuffer[MSG_HEADER_MAX_SIZE];
TReadHelper read_helper(&stream);
TChecksumHelper checksum_helper(csBuffer);
int32 flattenedSize;
try {
// Get the message version
read_helper(fMagic);
fSwapped = false;
if (fMagic == '1BOF') {
fSwapped = true;
} else if (fMagic == 'FOB1') {
fSwapped = false;
} else {
// This is *not* a message
return B_NOT_A_MESSAGE;
}
read_helper.SetSwap(fSwapped);
// get the checksum
read_helper(checkSum);
// get the size
read_helper(flattenedSize);
checksum_helper.Cache(flattenedSize);
// Get the what
read_helper(fWhat);
checksum_helper.Cache(fWhat);
// Get the flags
read_helper(fFlags);
checksum_helper.Cache(fFlags);
if (fFlags & MSG_FLAG_BIG_ENDIAN) {
// TODO: ???
// Isn't this already indicated by the byte order of the message version?
}
if (fFlags & MSG_FLAG_INCL_TARGET) {
// Get the target data
read_helper(fTargetToken);
checksum_helper.Cache(fTargetToken);
}
if (fFlags & MSG_FLAG_INCL_REPLY) {
// Get the reply port
read_helper(fReplyPort);
read_helper(fReplyToken);
read_helper(fReplyTeam);
checksum_helper.Cache(fReplyPort);
checksum_helper.Cache(fReplyToken);
checksum_helper.Cache(fReplyTeam);
// Get the "big flags"
uint8 bigFlags;
// Get the preferred flag
read_helper(bigFlags);
checksum_helper.Cache(bigFlags);
fPreferredTarget = bigFlags;
// Get the reply requirement flag
read_helper(bigFlags);
checksum_helper.Cache(bigFlags);
fReplyRequired = bigFlags;
// Get the reply done flag
read_helper(bigFlags);
checksum_helper.Cache(bigFlags);
fReplyDone = bigFlags;
// Get the "is reply" flag
read_helper(bigFlags);
checksum_helper.Cache(bigFlags);
fIsReply = bigFlags;
}
} catch (status_t& e) {
return e;
}
if (checkSum != checksum_helper.CheckSum())
return B_NOT_A_MESSAGE;
fBodySize = flattenedSize - CalculateHeaderSize();
return B_OK;
}
// ReadFrom
void
BMessage::Header::ReadFrom(const BMessage &message)
{
fMagic = MSG_FIELD_VERSION;
fBodySize = message.fBody->FlattenedSize();
fWhat = message.what;
fFlags = 0;
#ifdef B_HOST_IS_BENDIAN
fFlags |= MSG_FLAG_BIG_ENDIAN;
#endif
if (message.HasSpecifiers())
fFlags |= MSG_FLAG_SCRIPT_MSG;
if (message.fTarget != B_NULL_TOKEN)
fFlags |= MSG_FLAG_INCL_TARGET;
if (message.fReplyTo.port >= 0 &&
message.fReplyTo.target != B_NULL_TOKEN &&
message.fReplyTo.team >= 0) {
fFlags |= MSG_FLAG_INCL_REPLY;
}
fTargetToken = message.fTarget;
fReplyPort = message.fReplyTo.port;
fReplyToken = message.fReplyTo.target;
fReplyTeam = message.fReplyTo.team;
fPreferredTarget = message.fPreferred;
fReplyRequired = message.fReplyRequired;
fReplyDone = message.fReplyDone;
fIsReply = message.fIsReply;
}
// WriteTo
status_t
BMessage::Header::WriteTo(BDataIO &stream)
{
status_t err = B_OK;
int32 data;
// Write the version of the binary data format
data = fMagic;
write_helper(&stream, (const void*)&data, sizeof (data), err);
if (!err) {
// compute checksum
data = CalculateCheckSum();
write_helper(&stream, (const void*)&data, sizeof (data), err);
}
if (!err) {
// Write the flattened size of the entire message
data = CalculateHeaderSize() + fBodySize;
write_helper(&stream, (const void*)&data, sizeof (data), err);
}
if (!err) {
// Write the 'what' member
write_helper(&stream, (const void*)&fWhat, sizeof (fWhat), err);
}
if (!err) {
// Write the header flags
write_helper(&stream, (const void*)&fFlags, sizeof (fFlags), err);
}
// Write targeting info if necessary
if (!err && (fFlags & MSG_FLAG_INCL_TARGET)) {
data = fPreferredTarget ? B_PREFERRED_TOKEN : fTargetToken;
write_helper(&stream, (const void*)&data, sizeof (data), err);
}
// Write reply info if necessary
if (!err && (fFlags & MSG_FLAG_INCL_REPLY)) {
write_helper(&stream, (const void*)&fReplyPort, sizeof(fReplyPort),
err);
if (!err) {
write_helper(&stream, (const void*)&fReplyToken,
sizeof(fReplyToken), err);
}
if (!err) {
write_helper(&stream, (const void*)&fReplyTeam,
sizeof(fReplyTeam), err);
}
uint8 bigFlags;
if (!err) {
bigFlags = fPreferredTarget ? 1 : 0;
write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
err);
}
if (!err)
{
bigFlags = fReplyRequired ? 1 : 0;
write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
err);
}
if (!err)
{
bigFlags = fReplyDone ? 1 : 0;
write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
err);
}
if (!err)
{
bigFlags = fIsReply ? 1 : 0;
write_helper(&stream, (const void*)&bigFlags, sizeof(bigFlags),
err);
}
}
return err;
}
// WriteTo
void
BMessage::Header::WriteTo(BMessage &message)
{
// Make way for the new data
message.MakeEmpty();
message.what = fWhat;
message.fHasSpecifiers = fFlags & MSG_FLAG_SCRIPT_MSG;
if (fFlags & MSG_FLAG_INCL_TARGET) {
// Get the target data
message.fTarget = fTargetToken;
}
if (fFlags & MSG_FLAG_INCL_REPLY) {
// Get the reply port
message.fReplyTo.port = fReplyPort;
message.fReplyTo.target = fReplyToken;
message.fReplyTo.team = fReplyTeam;
message.fWasDelivered = true;
message.fPreferred = fPreferredTarget;
if (fPreferredTarget)
message.fTarget = B_PREFERRED_TOKEN;
message.fReplyRequired = fReplyRequired;
message.fReplyDone = fReplyDone;
message.fIsReply = fIsReply;
}
}
// CalculateCheckSum
uint32
BMessage::Header::CalculateCheckSum() const
{
uchar csBuffer[MSG_HEADER_MAX_SIZE];
TChecksumHelper checksum_helper(csBuffer);
int32 flattenedSize = CalculateHeaderSize() + fBodySize;
checksum_helper.Cache(flattenedSize);
checksum_helper.Cache(fWhat);
checksum_helper.Cache(fFlags);
if (fFlags & MSG_FLAG_INCL_TARGET)
checksum_helper.Cache(fTargetToken);
if (fFlags & MSG_FLAG_INCL_REPLY) {
checksum_helper.Cache(fReplyPort);
checksum_helper.Cache(fReplyToken);
checksum_helper.Cache(fReplyTeam);
// big flags
uint8 bigFlags = (fPreferredTarget ? 1 : 0);
checksum_helper.Cache(bigFlags);
bigFlags = (fReplyRequired ? 1 : 0);
checksum_helper.Cache(bigFlags);
bigFlags = (fReplyDone ? 1 : 0);
checksum_helper.Cache(bigFlags);
bigFlags = (fIsReply ? 1 : 0);
checksum_helper.Cache(bigFlags);
}
return checksum_helper.CheckSum();
}
// CalculateHeaderSize
uint32
BMessage::Header::CalculateHeaderSize() const
{
ssize_t size = min_hdr_size();
if (fTargetToken != B_NULL_TOKEN)
size += sizeof (fTargetToken);
if (fReplyPort >= 0 && fReplyToken != B_NULL_TOKEN && fReplyTeam >= 0) {
size += sizeof (fReplyPort);
size += sizeof (fReplyToken);
size += sizeof (fReplyTeam);
size += 4; // For the "big" flags
}
return size;
}
// SetTarget
void
BMessage::Header::SetTarget(int32 token, bool preferred)
{
fTargetToken = token;
if (fTargetToken == B_NULL_TOKEN)
fFlags &= ~MSG_FLAG_INCL_TARGET;
else
fFlags |= MSG_FLAG_INCL_TARGET;
fPreferredTarget = preferred;
}
// #pragma mark -
void BMessage::_ReservedMessage1() {}
void BMessage::_ReservedMessage2() {}
void BMessage::_ReservedMessage3() {}
@ -591,11 +930,14 @@ status_t BMessage::Unflatten(const char* flat_buffer)
//------------------------------------------------------------------------------
status_t BMessage::Unflatten(BDataIO* stream)
{
bool swap;
status_t err = unflatten_hdr(stream, swap);
Header header;
status_t err = header.ReadFrom(*stream);
if (!err)
{
header.WriteTo(*this);
bool swap = header.IsSwapped();
TReadHelper reader(stream, swap);
int8 flags;
type_code type;
@ -1462,242 +1804,24 @@ BPoint BMessage::FindPoint(const char* name, int32 n) const
FindPoint(name, n, &p);
return p;
}
//------------------------------------------------------------------------------
status_t BMessage::flatten_hdr(BDataIO* stream) const
{
status_t err = B_OK;
int32 data = MSG_FIELD_VERSION;
// Write the version of the binary data format
write_helper(stream, (const void*)&data, sizeof (data), err);
if (!err)
{
// faked up checksum; we'll fix it up later
write_helper(stream, (const void*)&data, sizeof (data), err);
}
if (!err)
{
// Write the flattened size of the entire message
data = fBody->FlattenedSize() + calc_hdr_size(0);
write_helper(stream, (const void*)&data, sizeof (data), err);
}
if (!err)
{
// Write the 'what' member
write_helper(stream, (const void*)&what, sizeof (what), err);
}
uint8 flags = 0;
#ifdef B_HOST_IS_BENDIAN
flags |= MSG_FLAG_BIG_ENDIAN;
#endif
if (HasSpecifiers())
{
flags |= MSG_FLAG_SCRIPT_MSG;
}
if (fTarget != B_NULL_TOKEN)
{
flags |= MSG_FLAG_INCL_TARGET;
}
if (fReplyTo.port >= 0 &&
fReplyTo.target != B_NULL_TOKEN &&
fReplyTo.team >= 0)
{
flags |= MSG_FLAG_INCL_REPLY;
}
if (!err)
{
// Write the header flags
write_helper(stream, (const void*)&flags, sizeof (flags), err);
}
// Write targeting info if necessary
if (!err && (flags & MSG_FLAG_INCL_TARGET))
{
data = fPreferred ? B_PREFERRED_TOKEN : fTarget;
write_helper(stream, (const void*)&data, sizeof (data), err);
}
// Write reply info if necessary
if (!err && (flags & MSG_FLAG_INCL_REPLY))
{
write_helper(stream, (const void*)&fReplyTo.port,
sizeof (fReplyTo.port), err);
if (!err)
{
write_helper(stream, (const void*)&fReplyTo.target,
sizeof (fReplyTo.target), err);
}
if (!err)
{
write_helper(stream, (const void*)&fReplyTo.team,
sizeof (fReplyTo.team), err);
}
uint8 bigFlags;
if (!err)
{
bigFlags = fPreferred ? 1 : 0;
write_helper(stream, (const void*)&bigFlags,
sizeof (bigFlags), err);
}
if (!err)
{
bigFlags = fReplyRequired ? 1 : 0;
write_helper(stream, (const void*)&bigFlags,
sizeof (bigFlags), err);
}
if (!err)
{
bigFlags = fReplyDone ? 1 : 0;
write_helper(stream, (const void*)&bigFlags,
sizeof (bigFlags), err);
}
if (!err)
{
bigFlags = fIsReply ? 1 : 0;
write_helper(stream, (const void*)&bigFlags,
sizeof (bigFlags), err);
}
}
return err;
}
//------------------------------------------------------------------------------
status_t BMessage::unflatten_hdr(BDataIO* stream, bool& swap)
{
status_t err = B_OK;
int32 data;
int32 checksum;
uchar csBuffer[MSG_HEADER_MAX_SIZE];
TReadHelper read_helper(stream);
TChecksumHelper checksum_helper(csBuffer);
try {
// Get the message version
read_helper(data);
if (data == '1BOF')
{
swap = true;
}
else if (data == 'FOB1')
{
swap = false;
}
else
{
// This is *not* a message
return B_NOT_A_MESSAGE;
}
// Make way for the new data
MakeEmpty();
read_helper.SetSwap(swap);
// get the checksum
read_helper(checksum);
// get the size
read_helper(data);
checksum_helper.Cache(data);
// Get the what
read_helper(what);
checksum_helper.Cache(what);
// Get the flags
uint8 flags = 0;
read_helper(flags);
checksum_helper.Cache(flags);
fHasSpecifiers = flags & MSG_FLAG_SCRIPT_MSG;
if (flags & MSG_FLAG_BIG_ENDIAN)
{
// TODO: ???
// Isn't this already indicated by the byte order of the message version?
}
if (flags & MSG_FLAG_INCL_TARGET)
{
// Get the target data
read_helper(data);
checksum_helper.Cache(data);
fTarget = data;
}
if (flags & MSG_FLAG_INCL_REPLY)
{
// Get the reply port
read_helper(fReplyTo.port);
read_helper(fReplyTo.target);
read_helper(fReplyTo.team);
checksum_helper.Cache(fReplyTo.port);
checksum_helper.Cache(fReplyTo.target);
checksum_helper.Cache(fReplyTo.team);
fWasDelivered = true;
// Get the "big flags"
uint8 bigFlags;
// Get the preferred flag
read_helper(bigFlags);
checksum_helper.Cache(bigFlags);
fPreferred = bigFlags;
if (fPreferred)
{
fTarget = B_PREFERRED_TOKEN;
}
// Get the reply requirement flag
read_helper(bigFlags);
checksum_helper.Cache(bigFlags);
fReplyRequired = bigFlags;
// Get the reply done flag
read_helper(bigFlags);
checksum_helper.Cache(bigFlags);
fReplyDone = bigFlags;
// Get the "is reply" flag
read_helper(bigFlags);
checksum_helper.Cache(bigFlags);
fIsReply = bigFlags;
}
}
catch (status_t& e)
{
err = e;
}
if (checksum != checksum_helper.CheckSum())
err = B_NOT_A_MESSAGE;
return err;
}
//------------------------------------------------------------------------------
status_t BMessage::real_flatten(char* result, ssize_t size) const
status_t
BMessage::real_flatten(char* result, ssize_t size) const
{
BMemoryIO stream((void*)result, size);
status_t err = real_flatten(&stream);
return real_flatten(&stream);
if (!err)
{
// Fixup the checksum; it is calculated on data size, what, flags,
// and target info (including big flags if appropriate)
((uint32*)result)[1] = _checksum_((uchar*)result + (sizeof (uint32) * 2),
calc_hdr_size(0) - (sizeof (uint32) * 2));
}
return err;
}
//------------------------------------------------------------------------------
status_t BMessage::real_flatten(BDataIO* stream) const
{
status_t err = flatten_hdr(stream);
Header header(*this);
status_t err = header.WriteTo(*stream);
if (!err)
{
err = fBody->Flatten(stream);
}
return err;
}
@ -1759,19 +1883,6 @@ BMessage::calc_hdr_size(uchar flags) const
return size;
}
//------------------------------------------------------------------------------
ssize_t BMessage::min_hdr_size() const
{
ssize_t size = 0;
size += 4; // version
size += 4; // checksum
size += 4; // flattened size
size += 4; // 'what'
size += 1; // flags
return size;
}
//------------------------------------------------------------------------------
status_t BMessage::_send_(port_id port, int32 token, bool preferred,
bigtime_t timeout, bool reply_required,
BMessenger& reply_to) const
@ -1888,6 +1999,10 @@ error:
}
// Note, that in case of a flattened BMessage setting the target token will
// change the header size, if no token was set when the message was flattened.
// Hence the message would need to unflattened and flattened again before it
// can be sent.
status_t
BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
int32 token, bool preferred, bigtime_t timeout)
@ -1905,24 +2020,35 @@ BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
header->replyToken = B_NULL_TOKEN;
} else if (*(int32*)data == '1BOF' || *(int32*)data == 'FOB1') {
// bool swap = (*(int32*)data == '1BOF');
// TODO: Replace the target token. This is not so simple, since the
// position of the target token is not always the same. It can even
// happen that no target token is included at all (the one who is
// flattening the message must set a dummy token at least).
// dummy implementation to make it work at least
// unflatten the message
BMessage message;
status_t error = message.Unflatten((const char*)data);
// get the header
BMemoryIO stream(data, size);
Header header;
status_t error = header.ReadFrom(stream);
if (error != B_OK)
return error;
// send the message
BMessenger messenger;
return message._send_(port, token, preferred, timeout, false,
messenger);
if (!header.HasTarget()) {
// fallback implementation -- the header size would change by
// setting the token
// unflatten the message
BMessage message;
error = message.Unflatten((const char*)data);
if (error != B_OK)
return error;
// send the message
BMessenger messenger;
return message._send_(port, token, preferred, timeout, false,
messenger);
}
// set the target token and replace the header
header.SetTarget(token, preferred);
stream.Seek(0LL, SEEK_SET);
error = header.WriteTo(stream);
if (error != B_OK)
return error;
} else {
return B_NOT_A_MESSAGE;
}
@ -2107,3 +2233,17 @@ convert_message(const KMessage *fromMessage, BMessage *toMessage)
return B_OK;
}
static
ssize_t
min_hdr_size()
{
ssize_t size = 0;
size += 4; // version
size += 4; // checksum
size += 4; // flattened size
size += 4; // 'what'
size += 1; // flags
return size;
}