Skip to content

Commit d175947

Browse files
committed
Reduce impact of media plugin message parsing when many media surfaces present with binary llsd
1 parent 341d3c4 commit d175947

10 files changed

Lines changed: 78 additions & 47 deletions

indra/llplugin/llplugininstance.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ void LLPluginInstance::sendMessage(const std::string &message)
102102
if(mPluginSendMessageFunction)
103103
{
104104
LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL;
105-
mPluginSendMessageFunction(message.c_str(), &mPluginUserData);
105+
mPluginSendMessageFunction(message.data(), message.size(), &mPluginUserData);
106106
}
107107
else
108108
{
@@ -119,28 +119,31 @@ void LLPluginInstance::idle(void)
119119
}
120120

121121
// static
122-
void LLPluginInstance::staticReceiveMessage(const char *message_string, void **user_data)
122+
void LLPluginInstance::staticReceiveMessage(const char *message_string, size_t message_size, void **user_data)
123123
{
124124
// TODO: validate that the user_data argument is still a valid LLPluginInstance pointer
125125
// we could also use a key that's looked up in a map (instead of a direct pointer) for safety, but that's probably overkill
126126
LLPluginInstance *self = (LLPluginInstance*)*user_data;
127-
self->receiveMessage(message_string);
127+
self->receiveMessage(message_string, message_size);
128128
}
129129

130130
/**
131131
* Plugin receives message from plugin loader shell.
132132
*
133-
* @param[in] message_string Message
133+
* @param[in] message_string Message bytes (binary LLSD, may contain embedded NULs)
134+
* @param[in] message_size Length of message_string in bytes
134135
*/
135-
void LLPluginInstance::receiveMessage(const char *message_string)
136+
void LLPluginInstance::receiveMessage(const char *message_string, size_t message_size)
136137
{
138+
// Reconstruct the message with its exact length: the payload is binary and
139+
// may contain embedded NULs, so it can't be treated as a C string.
140+
std::string message(message_string, message_size);
137141
if(mOwner)
138142
{
139-
LL_DEBUGS("Plugin") << "processing incoming message: \"" << message_string << "\"" << LL_ENDL;
140-
mOwner->receivePluginMessage(message_string);
143+
mOwner->receivePluginMessage(message);
141144
}
142145
else
143146
{
144-
LL_WARNS("Plugin") << "dropping incoming message: \"" << message_string << "\"" << LL_ENDL;
147+
LL_WARNS("Plugin") << "dropping incoming message: \"" << message << "\"" << LL_ENDL;
145148
}
146149
}

indra/llplugin/llplugininstance.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,11 @@ class LLPluginInstance
6767

6868
/** The signature of the function for sending a message from plugin to plugin loader shell.
6969
*
70-
* @param[in] message_string Null-terminated C string
70+
* @param[in] message_string Message bytes (may contain embedded NULs - it is binary LLSD)
71+
* @param[in] message_size Length of message_string in bytes
7172
* @param[in] user_data The opaque reference that the callee supplied during setup.
7273
*/
73-
typedef void (*sendMessageFunction) (const char *message_string, void **user_data);
74+
typedef void (*sendMessageFunction) (const char *message_string, size_t message_size, void **user_data);
7475

7576
/** The signature of the plugin init function. TODO:DOC check direction (pluging loader shell to plugin?)
7677
*
@@ -87,8 +88,8 @@ class LLPluginInstance
8788
static void setStaticInitFunction(pluginInitFunction func);
8889

8990
private:
90-
static void staticReceiveMessage(const char *message_string, void **user_data);
91-
void receiveMessage(const char *message_string);
91+
static void staticReceiveMessage(const char *message_string, size_t message_size, void **user_data);
92+
void receiveMessage(const char *message_string, size_t message_size);
9293

9394
void *mPluginUserData;
9495
sendMessageFunction mPluginSendMessageFunction;

indra/llplugin/llpluginmessage.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,8 @@ std::string LLPluginMessage::generate(void) const
358358
std::ostringstream result;
359359

360360
// Pretty XML may be slightly easier to deal with while debugging...
361-
// LLSDSerialize::toXML(mMessage, result);
362-
LLSDSerialize::toPrettyXML(mMessage, result);
361+
// LLSDSerialize::toPrettyXML(mMessage, result);
362+
LLSDSerialize::toBinary(mMessage, result);
363363

364364
return result.str();
365365
}
@@ -374,9 +374,10 @@ int LLPluginMessage::parse(const std::string &message)
374374
// clear any previous state
375375
clear();
376376

377-
std::istringstream input(message);
377+
boost::iostreams::stream<boost::iostreams::array_source> input(message.data(), message.size());
378378

379-
S32 parse_result = LLSDSerialize::fromXML(mMessage, input);
379+
//S32 parse_result = LLSDSerialize::fromXML(mMessage, input);
380+
S32 parse_result = LLSDSerialize::fromBinary(mMessage, input, LLSDSerialize::SIZE_UNLIMITED);
380381

381382
return (int)parse_result;
382383
}

indra/llplugin/llpluginmessagepipe.cpp

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@
3333

3434
#include "llapr.h"
3535

36-
static const char MESSAGE_DELIMITER = '\0';
36+
// Each message on the wire is framed with a 4-byte big-endian length prefix
37+
// followed by exactly that many payload bytes. A single delimiter byte can't
38+
// be used because the payload is now binary LLSD, which contains embedded NULs
39+
// (and every other byte value) in its length/size fields.
40+
static constexpr size_t MESSAGE_HEADER_SIZE = 4;
3741

3842
LLPluginMessagePipeOwner::LLPluginMessagePipeOwner() :
3943
mMessagePipe(NULL),
@@ -121,8 +125,16 @@ bool LLPluginMessagePipe::addMessage(const std::string &message)
121125
mOutputStartIndex = 0;
122126
}
123127

128+
// Frame the message with a 4-byte big-endian length prefix.
129+
U32 msg_size = static_cast<U32>(message.size());
130+
const char header[MESSAGE_HEADER_SIZE] = {
131+
static_cast<char>((msg_size >> 24) & 0xFF),
132+
static_cast<char>((msg_size >> 16) & 0xFF),
133+
static_cast<char>((msg_size >> 8) & 0xFF),
134+
static_cast<char>(msg_size & 0xFF)
135+
};
136+
mOutput.append(header, MESSAGE_HEADER_SIZE);
124137
mOutput += message;
125-
mOutput += MESSAGE_DELIMITER; // message separator
126138

127139
return true;
128140
}
@@ -177,9 +189,10 @@ bool LLPluginMessagePipe::pumpOutput()
177189

178190
LLMutexLock lock(&mOutputMutex);
179191

180-
const char * output_data = &(mOutput.data()[mOutputStartIndex]);
181-
if(*output_data != '\0')
192+
if(mOutput.size() > mOutputStartIndex)
182193
{
194+
const char * output_data = &(mOutput.data()[mOutputStartIndex]);
195+
183196
// write any outgoing messages
184197
in_size = (apr_size_t) (mOutput.size() - mOutputStartIndex);
185198
out_size = in_size;
@@ -370,27 +383,39 @@ bool LLPluginMessagePipe::pumpInput(F64 timeout)
370383

371384
void LLPluginMessagePipe::processInput(void)
372385
{
373-
// Look for input delimiter(s) in the input buffer.
374-
size_t delim;
375386
mInputMutex.lock();
376-
while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos)
387+
// Each message is a 4-byte big-endian length followed by that many payload
388+
// bytes. Dispatch complete messages, leaving any trailing partial message
389+
// in the buffer to be completed by a later read.
390+
while(mInput.size() >= MESSAGE_HEADER_SIZE)
377391
{
378-
// Let the owner process this message
379-
if (mOwner)
392+
const U8* buf = reinterpret_cast<const U8*>(mInput.data());
393+
size_t msg_size =
394+
(static_cast<size_t>(buf[0]) << 24) |
395+
(static_cast<size_t>(buf[1]) << 16) |
396+
(static_cast<size_t>(buf[2]) << 8) |
397+
static_cast<size_t>(buf[3]);
398+
399+
if(mInput.size() < MESSAGE_HEADER_SIZE + msg_size)
380400
{
381-
// Pull the message out of the input buffer before calling receiveMessageRaw.
382-
// It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request)
383-
// and this guarantees that the messages will get dequeued correctly.
384-
std::string message(mInput, 0, delim);
385-
mInput.erase(0, delim + 1);
386-
mInputMutex.unlock();
387-
mOwner->receiveMessageRaw(message);
388-
mInputMutex.lock();
401+
// The full message body hasn't arrived yet; wait for more.
402+
break;
389403
}
390-
else
404+
405+
if(!mOwner)
391406
{
392407
LL_WARNS("Plugin") << "!mOwner" << LL_ENDL;
408+
break;
393409
}
410+
411+
// Pull the message out of the input buffer before calling receiveMessageRaw.
412+
// It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request)
413+
// and this guarantees that the messages will get dequeued correctly.
414+
std::string message(mInput, MESSAGE_HEADER_SIZE, msg_size);
415+
mInput.erase(0, MESSAGE_HEADER_SIZE + msg_size);
416+
mInputMutex.unlock();
417+
mOwner->receiveMessageRaw(message);
418+
mInputMutex.lock();
394419
}
395420
mInputMutex.unlock();
396421
}

indra/media_plugins/base/media_plugin_base.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,14 @@ void MediaPluginBase::setStatus(EStatus status)
104104
* @param[in] user_data Message data
105105
*
106106
*/
107-
void MediaPluginBase::staticReceiveMessage(const char *message_string, void **user_data)
107+
void MediaPluginBase::staticReceiveMessage(const char *message_string, size_t message_size, void **user_data)
108108
{
109109
MediaPluginBase *self = (MediaPluginBase*)*user_data;
110110

111111
if(self != NULL)
112112
{
113-
self->receiveMessage(message_string);
113+
// Reconstruct with the exact length: binary LLSD may contain NULs.
114+
self->receiveMessage(std::string(message_string, message_size));
114115

115116
// If the plugin has processed the delete message, delete it.
116117
if(self->mDeleteMe)
@@ -130,7 +131,7 @@ void MediaPluginBase::staticReceiveMessage(const char *message_string, void **us
130131
void MediaPluginBase::sendMessage(const LLPluginMessage &message)
131132
{
132133
std::string output = message.generate();
133-
mHostSendFunction(output.c_str(), &mHostUserData);
134+
mHostSendFunction(output.data(), output.size(), &mHostUserData);
134135
}
135136

136137
/**

indra/media_plugins/base/media_plugin_base.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ class MediaPluginBase
8282
virtual ~MediaPluginBase() {}
8383

8484
/** Handle received message from plugin loader shell. */
85-
virtual void receiveMessage(const char *message_string) = 0;
85+
virtual void receiveMessage(const std::string &message_string) = 0;
8686

87-
static void staticReceiveMessage(const char *message_string, void **user_data);
87+
static void staticReceiveMessage(const char *message_string, size_t message_size, void **user_data);
8888

8989
protected:
9090

indra/media_plugins/cef/media_plugin_cef.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ class MediaPluginCEF :
234234
~MediaPluginCEF();
235235

236236
/*virtual*/
237-
void receiveMessage(const char* message_string);
237+
void receiveMessage(const std::string& message_string);
238238

239239
private:
240240
bool init();
@@ -1078,7 +1078,7 @@ void MediaPluginCEF::authResponse(LLPluginMessage &message)
10781078

10791079
////////////////////////////////////////////////////////////////////////////////
10801080
//
1081-
void MediaPluginCEF::receiveMessage(const char* message_string)
1081+
void MediaPluginCEF::receiveMessage(const std::string& message_string)
10821082
{
10831083
// std::cerr << "MediaPluginCEF::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
10841084
LLPluginMessage message_in;

indra/media_plugins/example/media_plugin_example.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class mediaPluginExample :
4545
mediaPluginExample(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
4646
~mediaPluginExample();
4747

48-
/*virtual*/ void receiveMessage(const char* message_string);
48+
/*virtual*/ void receiveMessage(const std::string& message_string);
4949

5050
private:
5151
bool init();
@@ -89,7 +89,7 @@ mediaPluginExample::~mediaPluginExample()
8989

9090
////////////////////////////////////////////////////////////////////////////////
9191
//
92-
void mediaPluginExample::receiveMessage(const char* message_string)
92+
void mediaPluginExample::receiveMessage(const std::string& message_string)
9393
{
9494
// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
9595
LLPluginMessage message_in;

indra/media_plugins/gstreamer10/media_plugin_gstreamer10.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class MediaPluginGStreamer10 : public MediaPluginBase
6666
MediaPluginGStreamer10(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
6767
~MediaPluginGStreamer10();
6868

69-
/* virtual */ void receiveMessage(const char *message_string);
69+
/* virtual */ void receiveMessage(const std::string &message_string);
7070

7171
static bool startup();
7272
static bool closedown();
@@ -743,7 +743,7 @@ std::string MediaPluginGStreamer10::getVersion()
743743
return plugin_version;
744744
}
745745

746-
void MediaPluginGStreamer10::receiveMessage(const char *message_string)
746+
void MediaPluginGStreamer10::receiveMessage(const std::string &message_string)
747747
{
748748
LLPluginMessage message_in;
749749

indra/media_plugins/libvlc/media_plugin_libvlc.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class MediaPluginLibVLC :
5656
MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
5757
~MediaPluginLibVLC();
5858

59-
/*virtual*/ void receiveMessage(const char* message_string);
59+
/*virtual*/ void receiveMessage(const std::string& message_string);
6060

6161
private:
6262
bool init();
@@ -464,7 +464,7 @@ void MediaPluginLibVLC::setVolume(const F64 volume)
464464

465465
////////////////////////////////////////////////////////////////////////////////
466466
//
467-
void MediaPluginLibVLC::receiveMessage(const char* message_string)
467+
void MediaPluginLibVLC::receiveMessage(const std::string& message_string)
468468
{
469469
LLPluginMessage message_in;
470470

0 commit comments

Comments
 (0)