mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Bug 1121804 - Add websocket message listener. r=dglastonbury
1. Fix websocket listener, and implement a light-wight parser. 2. Handle the messages from clients by protobuf 3. Handle disconnection while receiving the close message.
This commit is contained in:
parent
d800fbc91b
commit
71a5472876
@ -10,9 +10,11 @@
|
||||
#include "nsAppRunner.h"
|
||||
#include "Composer2D.h"
|
||||
#include "Effects.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#include "TexturePoolOGL.h"
|
||||
#include "mozilla/layers/CompositorOGL.h"
|
||||
#include "mozilla/layers/CompositorParent.h"
|
||||
@ -66,7 +68,8 @@ using namespace layerscope;
|
||||
class DebugDataSender;
|
||||
class DebugGLData;
|
||||
|
||||
/* This class handle websocket protocol which included
|
||||
/*
|
||||
* This class handle websocket protocol which included
|
||||
* handshake and data frame's header
|
||||
*/
|
||||
class LayerScopeWebSocketHandler : public nsIInputStreamCallback {
|
||||
@ -81,203 +84,48 @@ public:
|
||||
|
||||
LayerScopeWebSocketHandler()
|
||||
: mState(NoHandshake)
|
||||
, mConnected(false)
|
||||
{ }
|
||||
|
||||
private:
|
||||
virtual ~LayerScopeWebSocketHandler()
|
||||
{
|
||||
if (mTransport) {
|
||||
mTransport->Close(NS_OK);
|
||||
}
|
||||
}
|
||||
void OpenStream(nsISocketTransport* aTransport);
|
||||
|
||||
public:
|
||||
void OpenStream(nsISocketTransport* aTransport) {
|
||||
MOZ_ASSERT(aTransport);
|
||||
|
||||
mTransport = aTransport;
|
||||
mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
|
||||
0,
|
||||
0,
|
||||
getter_AddRefs(mOutputStream));
|
||||
|
||||
nsCOMPtr<nsIInputStream> debugInputStream;
|
||||
mTransport->OpenInputStream(0,
|
||||
0,
|
||||
0,
|
||||
getter_AddRefs(debugInputStream));
|
||||
mInputStream = do_QueryInterface(debugInputStream);
|
||||
mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread());
|
||||
}
|
||||
|
||||
bool WriteToStream(void *ptr, uint32_t size) {
|
||||
if (mState == NoHandshake) {
|
||||
// Not yet handshake, just return true in case of
|
||||
// LayerScope remove this handle
|
||||
return true;
|
||||
} else if (mState == HandshakeFailed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate WebSocket header
|
||||
uint8_t wsHeader[10];
|
||||
int wsHeaderSize = 0;
|
||||
const uint8_t opcode = 0x2;
|
||||
wsHeader[0] = 0x80 | (opcode & 0x0f); // FIN + opcode;
|
||||
if (size <= 125) {
|
||||
wsHeaderSize = 2;
|
||||
wsHeader[1] = size;
|
||||
} else if (size < 65536) {
|
||||
wsHeaderSize = 4;
|
||||
wsHeader[1] = 0x7E;
|
||||
NetworkEndian::writeUint16(wsHeader + 2, size);
|
||||
} else {
|
||||
wsHeaderSize = 10;
|
||||
wsHeader[1] = 0x7F;
|
||||
NetworkEndian::writeUint64(wsHeader + 2, size);
|
||||
}
|
||||
|
||||
// Send WebSocket header
|
||||
nsresult rv;
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(reinterpret_cast<char*>(wsHeader),
|
||||
wsHeaderSize, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
uint32_t written = 0;
|
||||
while (written < size) {
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(reinterpret_cast<char*>(ptr) + written,
|
||||
size - written, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
written += cnt;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool WriteToStream(void *aPtr, uint32_t aSize);
|
||||
|
||||
// nsIInputStreamCallback
|
||||
NS_IMETHODIMP OnInputStreamReady(nsIAsyncInputStream *stream) MOZ_OVERRIDE
|
||||
{
|
||||
nsTArray<nsCString> protocolString;
|
||||
ReadInputStreamData(protocolString);
|
||||
NS_IMETHODIMP OnInputStreamReady(nsIAsyncInputStream *aStream) MOZ_OVERRIDE;
|
||||
|
||||
if (WebSocketHandshake(protocolString)) {
|
||||
mState = HandshakeSuccess;
|
||||
} else {
|
||||
mState = HandshakeFailed;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
void ReadInputStreamData(nsTArray<nsCString>& aProtocolString)
|
||||
{
|
||||
nsLineBuffer<char> lineBuffer;
|
||||
nsCString line;
|
||||
bool more = true;
|
||||
do {
|
||||
NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more);
|
||||
virtual ~LayerScopeWebSocketHandler() { CloseConnection(); }
|
||||
|
||||
if (line.Length() > 0) {
|
||||
aProtocolString.AppendElement(line);
|
||||
}
|
||||
} while (more && line.Length() > 0);
|
||||
}
|
||||
void ReadInputStreamData(nsTArray<nsCString>& aProtocolString);
|
||||
|
||||
bool WebSocketHandshake(nsTArray<nsCString>& aProtocolString)
|
||||
{
|
||||
nsresult rv;
|
||||
bool isWebSocket = false;
|
||||
nsCString version;
|
||||
nsCString wsKey;
|
||||
nsCString protocol;
|
||||
bool WebSocketHandshake(nsTArray<nsCString>& aProtocolString);
|
||||
|
||||
// Validate WebSocket client request.
|
||||
if (aProtocolString.Length() == 0)
|
||||
return false;
|
||||
nsresult HandleSocketMessage(nsIAsyncInputStream *aStream);
|
||||
|
||||
// Check that the HTTP method is GET
|
||||
const char* HTTP_METHOD = "GET ";
|
||||
if (strncmp(aProtocolString[0].get(), HTTP_METHOD, strlen(HTTP_METHOD)) != 0) {
|
||||
return false;
|
||||
}
|
||||
nsresult ProcessInput(uint8_t *aBuffer, uint32_t aCount);
|
||||
|
||||
for (uint32_t i = 1; i < aProtocolString.Length(); ++i) {
|
||||
const char* line = aProtocolString[i].get();
|
||||
const char* prop_pos = strchr(line, ':');
|
||||
if (prop_pos != nullptr) {
|
||||
nsCString key(line, prop_pos - line);
|
||||
nsCString value(prop_pos + 2);
|
||||
if (key.EqualsIgnoreCase("upgrade") &&
|
||||
value.EqualsIgnoreCase("websocket")) {
|
||||
isWebSocket = true;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-version")) {
|
||||
version = value;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-key")) {
|
||||
wsKey = value;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-protocol")) {
|
||||
protocol = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copied from WebsocketChannel, helper function to decode data frame
|
||||
void ApplyMask(uint32_t aMask, uint8_t *aData, uint64_t aLen);
|
||||
|
||||
if (!isWebSocket) {
|
||||
return false;
|
||||
}
|
||||
bool HandleDataFrame(uint8_t *aData, uint32_t aSize);
|
||||
|
||||
if (!(version.EqualsLiteral("7") ||
|
||||
version.EqualsLiteral("8") ||
|
||||
version.EqualsLiteral("13"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(protocol.EqualsIgnoreCase("binary"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Client request is valid. Start to generate and send server response.
|
||||
nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
nsAutoCString res;
|
||||
SHA1Sum sha1;
|
||||
nsCString combined(wsKey + guid);
|
||||
sha1.update(combined.get(), combined.Length());
|
||||
uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long.
|
||||
sha1.finish(digest);
|
||||
nsCString newString(reinterpret_cast<char*>(digest), SHA1Sum::kHashSize);
|
||||
Base64Encode(newString, res);
|
||||
|
||||
nsCString response("HTTP/1.1 101 Switching Protocols\r\n");
|
||||
response.AppendLiteral("Upgrade: websocket\r\n");
|
||||
response.AppendLiteral("Connection: Upgrade\r\n");
|
||||
response.Append(nsCString("Sec-WebSocket-Accept: ") + res + nsCString("\r\n"));
|
||||
response.AppendLiteral("Sec-WebSocket-Protocol: binary\r\n\r\n");
|
||||
uint32_t written = 0;
|
||||
uint32_t size = response.Length();
|
||||
while (written < size) {
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(const_cast<char*>(response.get()) + written,
|
||||
size - written, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
written += cnt;
|
||||
}
|
||||
mOutputStream->Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
void CloseConnection();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
nsCOMPtr<nsIAsyncInputStream> mInputStream;
|
||||
nsCOMPtr<nsISocketTransport> mTransport;
|
||||
SocketStateType mState;
|
||||
bool mConnected;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(LayerScopeWebSocketHandler, nsIInputStreamCallback);
|
||||
|
||||
|
||||
/*
|
||||
* Manage Websocket connections
|
||||
*/
|
||||
class LayerScopeWebSocketManager {
|
||||
public:
|
||||
LayerScopeWebSocketManager();
|
||||
@ -720,6 +568,12 @@ public:
|
||||
int aWidth = 0,
|
||||
int aHeight = 0);
|
||||
|
||||
static void SetLayersTreeSendable(bool aSet) {sLayersTreeSendable = aSet;}
|
||||
|
||||
static void SetLayersBufferSendable(bool aSet) {sLayersBufferSendable = aSet;}
|
||||
|
||||
static bool GetLayersTreeSendable() {return sLayersTreeSendable;}
|
||||
|
||||
// Sender private functions
|
||||
private:
|
||||
static void SendColor(void* aLayerRef,
|
||||
@ -736,8 +590,16 @@ private:
|
||||
static void SendYCbCrEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectYCbCr* aEffect);
|
||||
|
||||
// Data fields
|
||||
private:
|
||||
static bool sLayersTreeSendable;
|
||||
static bool sLayersBufferSendable;
|
||||
};
|
||||
|
||||
bool SenderHelper::sLayersTreeSendable = true;
|
||||
bool SenderHelper::sLayersBufferSendable = true;
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
// SenderHelper implementation
|
||||
@ -874,6 +736,8 @@ SenderHelper::SendEffectChain(GLContext* aGLContext,
|
||||
int aWidth,
|
||||
int aHeight)
|
||||
{
|
||||
if (!sLayersBufferSendable) return;
|
||||
|
||||
const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
|
||||
switch (primaryEffect->mType) {
|
||||
case EffectTypes::RGB: {
|
||||
@ -908,6 +772,430 @@ SenderHelper::SendEffectChain(GLContext* aGLContext,
|
||||
// TODO:
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
// LayerScopeWebSocketHandler implementation
|
||||
// ----------------------------------------------
|
||||
void
|
||||
LayerScopeWebSocketHandler::OpenStream(nsISocketTransport* aTransport)
|
||||
{
|
||||
MOZ_ASSERT(aTransport);
|
||||
|
||||
mTransport = aTransport;
|
||||
mTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING,
|
||||
0,
|
||||
0,
|
||||
getter_AddRefs(mOutputStream));
|
||||
|
||||
nsCOMPtr<nsIInputStream> debugInputStream;
|
||||
mTransport->OpenInputStream(0,
|
||||
0,
|
||||
0,
|
||||
getter_AddRefs(debugInputStream));
|
||||
mInputStream = do_QueryInterface(debugInputStream);
|
||||
mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread());
|
||||
}
|
||||
|
||||
bool
|
||||
LayerScopeWebSocketHandler::WriteToStream(void *aPtr,
|
||||
uint32_t aSize)
|
||||
{
|
||||
if (mState == NoHandshake) {
|
||||
// Not yet handshake, just return true in case of
|
||||
// LayerScope remove this handle
|
||||
return true;
|
||||
} else if (mState == HandshakeFailed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mOutputStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate WebSocket header
|
||||
uint8_t wsHeader[10];
|
||||
int wsHeaderSize = 0;
|
||||
const uint8_t opcode = 0x2;
|
||||
wsHeader[0] = 0x80 | (opcode & 0x0f); // FIN + opcode;
|
||||
if (aSize <= 125) {
|
||||
wsHeaderSize = 2;
|
||||
wsHeader[1] = aSize;
|
||||
} else if (aSize < 65536) {
|
||||
wsHeaderSize = 4;
|
||||
wsHeader[1] = 0x7E;
|
||||
NetworkEndian::writeUint16(wsHeader + 2, aSize);
|
||||
} else {
|
||||
wsHeaderSize = 10;
|
||||
wsHeader[1] = 0x7F;
|
||||
NetworkEndian::writeUint64(wsHeader + 2, aSize);
|
||||
}
|
||||
|
||||
// Send WebSocket header
|
||||
nsresult rv;
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(reinterpret_cast<char*>(wsHeader),
|
||||
wsHeaderSize, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
uint32_t written = 0;
|
||||
while (written < aSize) {
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(reinterpret_cast<char*>(aPtr) + written,
|
||||
aSize - written, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
written += cnt;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LayerScopeWebSocketHandler::OnInputStreamReady(nsIAsyncInputStream *aStream)
|
||||
{
|
||||
MOZ_ASSERT(mInputStream);
|
||||
|
||||
if (!mInputStream) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mConnected) {
|
||||
nsTArray<nsCString> protocolString;
|
||||
ReadInputStreamData(protocolString);
|
||||
|
||||
if (WebSocketHandshake(protocolString)) {
|
||||
mState = HandshakeSuccess;
|
||||
mConnected = true;
|
||||
mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread());
|
||||
} else {
|
||||
mState = HandshakeFailed;
|
||||
}
|
||||
return NS_OK;
|
||||
} else {
|
||||
return HandleSocketMessage(aStream);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerScopeWebSocketHandler::ReadInputStreamData(nsTArray<nsCString>& aProtocolString)
|
||||
{
|
||||
nsLineBuffer<char> lineBuffer;
|
||||
nsCString line;
|
||||
bool more = true;
|
||||
do {
|
||||
NS_ReadLine(mInputStream.get(), &lineBuffer, line, &more);
|
||||
|
||||
if (line.Length() > 0) {
|
||||
aProtocolString.AppendElement(line);
|
||||
}
|
||||
} while (more && line.Length() > 0);
|
||||
}
|
||||
|
||||
bool
|
||||
LayerScopeWebSocketHandler::WebSocketHandshake(nsTArray<nsCString>& aProtocolString)
|
||||
{
|
||||
nsresult rv;
|
||||
bool isWebSocket = false;
|
||||
nsCString version;
|
||||
nsCString wsKey;
|
||||
nsCString protocol;
|
||||
|
||||
// Validate WebSocket client request.
|
||||
if (aProtocolString.Length() == 0)
|
||||
return false;
|
||||
|
||||
// Check that the HTTP method is GET
|
||||
const char* HTTP_METHOD = "GET ";
|
||||
if (strncmp(aProtocolString[0].get(), HTTP_METHOD, strlen(HTTP_METHOD)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 1; i < aProtocolString.Length(); ++i) {
|
||||
const char* line = aProtocolString[i].get();
|
||||
const char* prop_pos = strchr(line, ':');
|
||||
if (prop_pos != nullptr) {
|
||||
nsCString key(line, prop_pos - line);
|
||||
nsCString value(prop_pos + 2);
|
||||
if (key.EqualsIgnoreCase("upgrade") &&
|
||||
value.EqualsIgnoreCase("websocket")) {
|
||||
isWebSocket = true;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-version")) {
|
||||
version = value;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-key")) {
|
||||
wsKey = value;
|
||||
} else if (key.EqualsIgnoreCase("sec-websocket-protocol")) {
|
||||
protocol = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isWebSocket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(version.EqualsLiteral("7") ||
|
||||
version.EqualsLiteral("8") ||
|
||||
version.EqualsLiteral("13"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(protocol.EqualsIgnoreCase("binary"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mOutputStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Client request is valid. Start to generate and send server response.
|
||||
nsAutoCString guid("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
nsAutoCString res;
|
||||
SHA1Sum sha1;
|
||||
nsCString combined(wsKey + guid);
|
||||
sha1.update(combined.get(), combined.Length());
|
||||
uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long.
|
||||
sha1.finish(digest);
|
||||
nsCString newString(reinterpret_cast<char*>(digest), SHA1Sum::kHashSize);
|
||||
Base64Encode(newString, res);
|
||||
|
||||
nsCString response("HTTP/1.1 101 Switching Protocols\r\n");
|
||||
response.AppendLiteral("Upgrade: websocket\r\n");
|
||||
response.AppendLiteral("Connection: Upgrade\r\n");
|
||||
response.Append(nsCString("Sec-WebSocket-Accept: ") + res + nsCString("\r\n"));
|
||||
response.AppendLiteral("Sec-WebSocket-Protocol: binary\r\n\r\n");
|
||||
uint32_t written = 0;
|
||||
uint32_t size = response.Length();
|
||||
while (written < size) {
|
||||
uint32_t cnt;
|
||||
rv = mOutputStream->Write(const_cast<char*>(response.get()) + written,
|
||||
size - written, &cnt);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
written += cnt;
|
||||
}
|
||||
mOutputStream->Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LayerScopeWebSocketHandler::HandleSocketMessage(nsIAsyncInputStream *aStream)
|
||||
{
|
||||
// The reading and parsing of this input stream is customized for layer viewer.
|
||||
const uint32_t cPacketSize = 1024;
|
||||
char buffer[cPacketSize];
|
||||
uint32_t count = 0;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
do {
|
||||
rv = mInputStream->Read((char *)buffer, cPacketSize, &count);
|
||||
|
||||
// TODO: combine packets if we have to read more than once
|
||||
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
mInputStream->AsyncWait(this, 0, 0, NS_GetCurrentThread());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
// NS_BASE_STREAM_CLOSED
|
||||
CloseConnection();
|
||||
break;
|
||||
}
|
||||
|
||||
rv = ProcessInput(reinterpret_cast<uint8_t *>(buffer), count);
|
||||
} while (NS_SUCCEEDED(rv) && mInputStream);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LayerScopeWebSocketHandler::ProcessInput(uint8_t *aBuffer,
|
||||
uint32_t aCount)
|
||||
{
|
||||
uint32_t avail = aCount;
|
||||
|
||||
// Decode Websocket data frame
|
||||
if (avail <= 2) {
|
||||
NS_WARNING("Packet size is less than 2 bytes");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// First byte, data type, only care the opcode
|
||||
// rsvBits: aBuffer[0] & 0x70 (0111 0000)
|
||||
uint8_t finBit = aBuffer[0] & 0x80; // 1000 0000
|
||||
uint8_t opcode = aBuffer[0] & 0x0F; // 0000 1111
|
||||
|
||||
if (!finBit) {
|
||||
NS_WARNING("We cannot handle multi-fragments messages in Layerscope websocket parser.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Second byte, data length
|
||||
uint8_t maskBit = aBuffer[1] & 0x80; // 1000 0000
|
||||
int64_t payloadLength64 = aBuffer[1] & 0x7F; // 0111 1111
|
||||
|
||||
if (!maskBit) {
|
||||
NS_WARNING("Client to Server should set the mask bit");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t framingLength = 2 + 4; // 4 for masks
|
||||
|
||||
if (payloadLength64 < 126) {
|
||||
if (avail < framingLength)
|
||||
return NS_OK;
|
||||
} else if (payloadLength64 == 126) {
|
||||
// 16 bit length field
|
||||
framingLength += 2;
|
||||
if (avail < framingLength) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
payloadLength64 = aBuffer[2] << 8 | aBuffer[3];
|
||||
} else {
|
||||
// 64 bit length
|
||||
framingLength += 8;
|
||||
if (avail < framingLength) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aBuffer[2] & 0x80) {
|
||||
// Section 4.2 says that the most significant bit MUST be
|
||||
// 0. (i.e. this is really a 63 bit value)
|
||||
NS_WARNING("High bit of 64 bit length set");
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
// copy this in case it is unaligned
|
||||
payloadLength64 = NetworkEndian::readInt64(aBuffer + 2);
|
||||
}
|
||||
|
||||
uint8_t *payload = aBuffer + framingLength;
|
||||
avail -= framingLength;
|
||||
|
||||
uint32_t payloadLength = static_cast<uint32_t>(payloadLength64);
|
||||
if (avail < payloadLength) {
|
||||
NS_WARNING("Packet size mismatch the payload length");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Apply mask
|
||||
uint32_t mask = NetworkEndian::readUint32(payload - 4);
|
||||
ApplyMask(mask, payload, payloadLength);
|
||||
|
||||
if (opcode == 0x8) {
|
||||
// opcode == 0x8 means connection close
|
||||
CloseConnection();
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
if (!HandleDataFrame(payload, payloadLength)) {
|
||||
NS_WARNING("Cannot decode payload data by the protocol buffer");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LayerScopeWebSocketHandler::ApplyMask(uint32_t aMask,
|
||||
uint8_t *aData,
|
||||
uint64_t aLen)
|
||||
{
|
||||
if (!aData || aLen == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Optimally we want to apply the mask 32 bits at a time,
|
||||
// but the buffer might not be alligned. So we first deal with
|
||||
// 0 to 3 bytes of preamble individually
|
||||
while (aLen && (reinterpret_cast<uintptr_t>(aData) & 3)) {
|
||||
*aData ^= aMask >> 24;
|
||||
aMask = RotateLeft(aMask, 8);
|
||||
aData++;
|
||||
aLen--;
|
||||
}
|
||||
|
||||
// perform mask on full words of data
|
||||
uint32_t *iData = reinterpret_cast<uint32_t *>(aData);
|
||||
uint32_t *end = iData + (aLen >> 2);
|
||||
NetworkEndian::writeUint32(&aMask, aMask);
|
||||
for (; iData < end; iData++) {
|
||||
*iData ^= aMask;
|
||||
}
|
||||
aMask = NetworkEndian::readUint32(&aMask);
|
||||
aData = (uint8_t *)iData;
|
||||
aLen = aLen % 4;
|
||||
|
||||
// There maybe up to 3 trailing bytes that need to be dealt with
|
||||
// individually
|
||||
while (aLen) {
|
||||
*aData ^= aMask >> 24;
|
||||
aMask = RotateLeft(aMask, 8);
|
||||
aData++;
|
||||
aLen--;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LayerScopeWebSocketHandler::HandleDataFrame(uint8_t *aData,
|
||||
uint32_t aSize)
|
||||
{
|
||||
// Handle payload data by protocol buffer
|
||||
auto p = MakeUnique<CommandPacket>();
|
||||
p->ParseFromArray(static_cast<void*>(aData), aSize);
|
||||
|
||||
if (!p->has_type()) {
|
||||
MOZ_ASSERT(false, "Protocol buffer decoding failed or cannot recongize it");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (p->type()) {
|
||||
case CommandPacket::LAYERS_TREE:
|
||||
if (p->has_value()) {
|
||||
SenderHelper::SetLayersTreeSendable(p->value());
|
||||
}
|
||||
break;
|
||||
|
||||
case CommandPacket::LAYERS_BUFFER:
|
||||
if (p->has_value()) {
|
||||
SenderHelper::SetLayersBufferSendable(p->value());
|
||||
}
|
||||
break;
|
||||
|
||||
case CommandPacket::NO_OP:
|
||||
default:
|
||||
NS_WARNING("Invalid message type");
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LayerScopeWebSocketHandler::CloseConnection()
|
||||
{
|
||||
WebSocketHelper::GetSocketManager()->CleanDebugData();
|
||||
if (mInputStream) {
|
||||
mInputStream->AsyncWait(nullptr, 0, 0, nullptr);
|
||||
mInputStream = nullptr;
|
||||
}
|
||||
if (mOutputStream) {
|
||||
mOutputStream = nullptr;
|
||||
}
|
||||
if (mTransport) {
|
||||
mTransport->Close(NS_BASE_STREAM_CLOSED);
|
||||
mTransport = nullptr;
|
||||
}
|
||||
mConnected = false;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
// LayerScopeWebSocketManager implementation
|
||||
// ----------------------------------------------
|
||||
@ -923,6 +1211,7 @@ LayerScopeWebSocketManager::LayerScopeWebSocketManager()
|
||||
|
||||
LayerScopeWebSocketManager::~LayerScopeWebSocketManager()
|
||||
{
|
||||
mServerSocket->Close();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1005,7 +1294,7 @@ void
|
||||
LayerScope::SendLayerDump(UniquePtr<Packet> aPacket)
|
||||
{
|
||||
// Protect this public function
|
||||
if (!CheckSendable()) {
|
||||
if (!CheckSendable() || !SenderHelper::GetLayersTreeSendable()) {
|
||||
return;
|
||||
}
|
||||
WebSocketHelper::GetSocketManager()->AppendDebugData(
|
||||
|
@ -27,6 +27,7 @@ void protobuf_ShutdownFile_LayerScopePacket_2eproto() {
|
||||
delete LayersPacket_Layer_Shadow::default_instance_;
|
||||
delete MetaPacket::default_instance_;
|
||||
delete Packet::default_instance_;
|
||||
delete CommandPacket::default_instance_;
|
||||
}
|
||||
|
||||
void protobuf_AddDesc_LayerScopePacket_2eproto() {
|
||||
@ -47,6 +48,7 @@ void protobuf_AddDesc_LayerScopePacket_2eproto() {
|
||||
LayersPacket_Layer_Shadow::default_instance_ = new LayersPacket_Layer_Shadow();
|
||||
MetaPacket::default_instance_ = new MetaPacket();
|
||||
Packet::default_instance_ = new Packet();
|
||||
CommandPacket::default_instance_ = new CommandPacket();
|
||||
FramePacket::default_instance_->InitAsDefaultInstance();
|
||||
ColorPacket::default_instance_->InitAsDefaultInstance();
|
||||
TexturePacket::default_instance_->InitAsDefaultInstance();
|
||||
@ -59,6 +61,7 @@ void protobuf_AddDesc_LayerScopePacket_2eproto() {
|
||||
LayersPacket_Layer_Shadow::default_instance_->InitAsDefaultInstance();
|
||||
MetaPacket::default_instance_->InitAsDefaultInstance();
|
||||
Packet::default_instance_->InitAsDefaultInstance();
|
||||
CommandPacket::default_instance_->InitAsDefaultInstance();
|
||||
::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_LayerScopePacket_2eproto);
|
||||
}
|
||||
|
||||
@ -3573,6 +3576,220 @@ void Packet::Swap(Packet* other) {
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
bool CommandPacket_CmdType_IsValid(int value) {
|
||||
switch(value) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
const CommandPacket_CmdType CommandPacket::NO_OP;
|
||||
const CommandPacket_CmdType CommandPacket::LAYERS_TREE;
|
||||
const CommandPacket_CmdType CommandPacket::LAYERS_BUFFER;
|
||||
const CommandPacket_CmdType CommandPacket::CmdType_MIN;
|
||||
const CommandPacket_CmdType CommandPacket::CmdType_MAX;
|
||||
const int CommandPacket::CmdType_ARRAYSIZE;
|
||||
#endif // _MSC_VER
|
||||
#ifndef _MSC_VER
|
||||
const int CommandPacket::kTypeFieldNumber;
|
||||
const int CommandPacket::kValueFieldNumber;
|
||||
#endif // !_MSC_VER
|
||||
|
||||
CommandPacket::CommandPacket()
|
||||
: ::google::protobuf::MessageLite() {
|
||||
SharedCtor();
|
||||
}
|
||||
|
||||
void CommandPacket::InitAsDefaultInstance() {
|
||||
}
|
||||
|
||||
CommandPacket::CommandPacket(const CommandPacket& from)
|
||||
: ::google::protobuf::MessageLite() {
|
||||
SharedCtor();
|
||||
MergeFrom(from);
|
||||
}
|
||||
|
||||
void CommandPacket::SharedCtor() {
|
||||
_cached_size_ = 0;
|
||||
type_ = 0;
|
||||
value_ = false;
|
||||
::memset(_has_bits_, 0, sizeof(_has_bits_));
|
||||
}
|
||||
|
||||
CommandPacket::~CommandPacket() {
|
||||
SharedDtor();
|
||||
}
|
||||
|
||||
void CommandPacket::SharedDtor() {
|
||||
if (this != default_instance_) {
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPacket::SetCachedSize(int size) const {
|
||||
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
|
||||
_cached_size_ = size;
|
||||
GOOGLE_SAFE_CONCURRENT_WRITES_END();
|
||||
}
|
||||
const CommandPacket& CommandPacket::default_instance() {
|
||||
if (default_instance_ == NULL) protobuf_AddDesc_LayerScopePacket_2eproto(); return *default_instance_;
|
||||
}
|
||||
|
||||
CommandPacket* CommandPacket::default_instance_ = NULL;
|
||||
|
||||
CommandPacket* CommandPacket::New() const {
|
||||
return new CommandPacket;
|
||||
}
|
||||
|
||||
void CommandPacket::Clear() {
|
||||
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
type_ = 0;
|
||||
value_ = false;
|
||||
}
|
||||
::memset(_has_bits_, 0, sizeof(_has_bits_));
|
||||
}
|
||||
|
||||
bool CommandPacket::MergePartialFromCodedStream(
|
||||
::google::protobuf::io::CodedInputStream* input) {
|
||||
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
|
||||
::google::protobuf::uint32 tag;
|
||||
while ((tag = input->ReadTag()) != 0) {
|
||||
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
|
||||
// required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1;
|
||||
case 1: {
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
|
||||
int value;
|
||||
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
|
||||
int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
|
||||
input, &value)));
|
||||
if (::mozilla::layers::layerscope::CommandPacket_CmdType_IsValid(value)) {
|
||||
set_type(static_cast< ::mozilla::layers::layerscope::CommandPacket_CmdType >(value));
|
||||
}
|
||||
} else {
|
||||
goto handle_uninterpreted;
|
||||
}
|
||||
if (input->ExpectTag(16)) goto parse_value;
|
||||
break;
|
||||
}
|
||||
|
||||
// optional bool value = 2;
|
||||
case 2: {
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
|
||||
parse_value:
|
||||
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
|
||||
bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
|
||||
input, &value_)));
|
||||
set_has_value();
|
||||
} else {
|
||||
goto handle_uninterpreted;
|
||||
}
|
||||
if (input->ExpectAtEnd()) return true;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
handle_uninterpreted:
|
||||
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
|
||||
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
|
||||
return true;
|
||||
}
|
||||
DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#undef DO_
|
||||
}
|
||||
|
||||
void CommandPacket::SerializeWithCachedSizes(
|
||||
::google::protobuf::io::CodedOutputStream* output) const {
|
||||
// required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1;
|
||||
if (has_type()) {
|
||||
::google::protobuf::internal::WireFormatLite::WriteEnum(
|
||||
1, this->type(), output);
|
||||
}
|
||||
|
||||
// optional bool value = 2;
|
||||
if (has_value()) {
|
||||
::google::protobuf::internal::WireFormatLite::WriteBool(2, this->value(), output);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int CommandPacket::ByteSize() const {
|
||||
int total_size = 0;
|
||||
|
||||
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
// required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1;
|
||||
if (has_type()) {
|
||||
total_size += 1 +
|
||||
::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
|
||||
}
|
||||
|
||||
// optional bool value = 2;
|
||||
if (has_value()) {
|
||||
total_size += 1 + 1;
|
||||
}
|
||||
|
||||
}
|
||||
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
|
||||
_cached_size_ = total_size;
|
||||
GOOGLE_SAFE_CONCURRENT_WRITES_END();
|
||||
return total_size;
|
||||
}
|
||||
|
||||
void CommandPacket::CheckTypeAndMergeFrom(
|
||||
const ::google::protobuf::MessageLite& from) {
|
||||
MergeFrom(*::google::protobuf::down_cast<const CommandPacket*>(&from));
|
||||
}
|
||||
|
||||
void CommandPacket::MergeFrom(const CommandPacket& from) {
|
||||
GOOGLE_CHECK_NE(&from, this);
|
||||
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
|
||||
if (from.has_type()) {
|
||||
set_type(from.type());
|
||||
}
|
||||
if (from.has_value()) {
|
||||
set_value(from.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommandPacket::CopyFrom(const CommandPacket& from) {
|
||||
if (&from == this) return;
|
||||
Clear();
|
||||
MergeFrom(from);
|
||||
}
|
||||
|
||||
bool CommandPacket::IsInitialized() const {
|
||||
if ((_has_bits_[0] & 0x00000001) != 0x00000001) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommandPacket::Swap(CommandPacket* other) {
|
||||
if (other != this) {
|
||||
std::swap(type_, other->type_);
|
||||
std::swap(value_, other->value_);
|
||||
std::swap(_has_bits_[0], other->_has_bits_[0]);
|
||||
std::swap(_cached_size_, other->_cached_size_);
|
||||
}
|
||||
}
|
||||
|
||||
::std::string CommandPacket::GetTypeName() const {
|
||||
return "mozilla.layers.layerscope.CommandPacket";
|
||||
}
|
||||
|
||||
|
||||
// @@protoc_insertion_point(namespace_scope)
|
||||
|
||||
} // namespace layerscope
|
||||
|
@ -45,6 +45,7 @@ class LayersPacket_Layer_Matrix;
|
||||
class LayersPacket_Layer_Shadow;
|
||||
class MetaPacket;
|
||||
class Packet;
|
||||
class CommandPacket;
|
||||
|
||||
enum LayersPacket_Layer_LayerType {
|
||||
LayersPacket_Layer_LayerType_UnknownLayer = 0,
|
||||
@ -98,6 +99,16 @@ const Packet_DataType Packet_DataType_DataType_MIN = Packet_DataType_FRAMESTART;
|
||||
const Packet_DataType Packet_DataType_DataType_MAX = Packet_DataType_META;
|
||||
const int Packet_DataType_DataType_ARRAYSIZE = Packet_DataType_DataType_MAX + 1;
|
||||
|
||||
enum CommandPacket_CmdType {
|
||||
CommandPacket_CmdType_NO_OP = 0,
|
||||
CommandPacket_CmdType_LAYERS_TREE = 1,
|
||||
CommandPacket_CmdType_LAYERS_BUFFER = 2
|
||||
};
|
||||
bool CommandPacket_CmdType_IsValid(int value);
|
||||
const CommandPacket_CmdType CommandPacket_CmdType_CmdType_MIN = CommandPacket_CmdType_NO_OP;
|
||||
const CommandPacket_CmdType CommandPacket_CmdType_CmdType_MAX = CommandPacket_CmdType_LAYERS_BUFFER;
|
||||
const int CommandPacket_CmdType_CmdType_ARRAYSIZE = CommandPacket_CmdType_CmdType_MAX + 1;
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class FramePacket : public ::google::protobuf::MessageLite {
|
||||
@ -1439,6 +1450,99 @@ class Packet : public ::google::protobuf::MessageLite {
|
||||
void InitAsDefaultInstance();
|
||||
static Packet* default_instance_;
|
||||
};
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class CommandPacket : public ::google::protobuf::MessageLite {
|
||||
public:
|
||||
CommandPacket();
|
||||
virtual ~CommandPacket();
|
||||
|
||||
CommandPacket(const CommandPacket& from);
|
||||
|
||||
inline CommandPacket& operator=(const CommandPacket& from) {
|
||||
CopyFrom(from);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static const CommandPacket& default_instance();
|
||||
|
||||
void Swap(CommandPacket* other);
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
CommandPacket* New() const;
|
||||
void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
|
||||
void CopyFrom(const CommandPacket& from);
|
||||
void MergeFrom(const CommandPacket& from);
|
||||
void Clear();
|
||||
bool IsInitialized() const;
|
||||
|
||||
int ByteSize() const;
|
||||
bool MergePartialFromCodedStream(
|
||||
::google::protobuf::io::CodedInputStream* input);
|
||||
void SerializeWithCachedSizes(
|
||||
::google::protobuf::io::CodedOutputStream* output) const;
|
||||
int GetCachedSize() const { return _cached_size_; }
|
||||
private:
|
||||
void SharedCtor();
|
||||
void SharedDtor();
|
||||
void SetCachedSize(int size) const;
|
||||
public:
|
||||
|
||||
::std::string GetTypeName() const;
|
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
typedef CommandPacket_CmdType CmdType;
|
||||
static const CmdType NO_OP = CommandPacket_CmdType_NO_OP;
|
||||
static const CmdType LAYERS_TREE = CommandPacket_CmdType_LAYERS_TREE;
|
||||
static const CmdType LAYERS_BUFFER = CommandPacket_CmdType_LAYERS_BUFFER;
|
||||
static inline bool CmdType_IsValid(int value) {
|
||||
return CommandPacket_CmdType_IsValid(value);
|
||||
}
|
||||
static const CmdType CmdType_MIN =
|
||||
CommandPacket_CmdType_CmdType_MIN;
|
||||
static const CmdType CmdType_MAX =
|
||||
CommandPacket_CmdType_CmdType_MAX;
|
||||
static const int CmdType_ARRAYSIZE =
|
||||
CommandPacket_CmdType_CmdType_ARRAYSIZE;
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
// required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1;
|
||||
inline bool has_type() const;
|
||||
inline void clear_type();
|
||||
static const int kTypeFieldNumber = 1;
|
||||
inline ::mozilla::layers::layerscope::CommandPacket_CmdType type() const;
|
||||
inline void set_type(::mozilla::layers::layerscope::CommandPacket_CmdType value);
|
||||
|
||||
// optional bool value = 2;
|
||||
inline bool has_value() const;
|
||||
inline void clear_value();
|
||||
static const int kValueFieldNumber = 2;
|
||||
inline bool value() const;
|
||||
inline void set_value(bool value);
|
||||
|
||||
// @@protoc_insertion_point(class_scope:mozilla.layers.layerscope.CommandPacket)
|
||||
private:
|
||||
inline void set_has_type();
|
||||
inline void clear_has_type();
|
||||
inline void set_has_value();
|
||||
inline void clear_has_value();
|
||||
|
||||
int type_;
|
||||
bool value_;
|
||||
|
||||
mutable int _cached_size_;
|
||||
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
|
||||
|
||||
friend void protobuf_AddDesc_LayerScopePacket_2eproto();
|
||||
friend void protobuf_AssignDesc_LayerScopePacket_2eproto();
|
||||
friend void protobuf_ShutdownFile_LayerScopePacket_2eproto();
|
||||
|
||||
void InitAsDefaultInstance();
|
||||
static CommandPacket* default_instance_;
|
||||
};
|
||||
// ===================================================================
|
||||
|
||||
|
||||
@ -2803,6 +2907,55 @@ inline ::mozilla::layers::layerscope::MetaPacket* Packet::release_meta() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// CommandPacket
|
||||
|
||||
// required .mozilla.layers.layerscope.CommandPacket.CmdType type = 1;
|
||||
inline bool CommandPacket::has_type() const {
|
||||
return (_has_bits_[0] & 0x00000001u) != 0;
|
||||
}
|
||||
inline void CommandPacket::set_has_type() {
|
||||
_has_bits_[0] |= 0x00000001u;
|
||||
}
|
||||
inline void CommandPacket::clear_has_type() {
|
||||
_has_bits_[0] &= ~0x00000001u;
|
||||
}
|
||||
inline void CommandPacket::clear_type() {
|
||||
type_ = 0;
|
||||
clear_has_type();
|
||||
}
|
||||
inline ::mozilla::layers::layerscope::CommandPacket_CmdType CommandPacket::type() const {
|
||||
return static_cast< ::mozilla::layers::layerscope::CommandPacket_CmdType >(type_);
|
||||
}
|
||||
inline void CommandPacket::set_type(::mozilla::layers::layerscope::CommandPacket_CmdType value) {
|
||||
GOOGLE_DCHECK(::mozilla::layers::layerscope::CommandPacket_CmdType_IsValid(value));
|
||||
set_has_type();
|
||||
type_ = value;
|
||||
}
|
||||
|
||||
// optional bool value = 2;
|
||||
inline bool CommandPacket::has_value() const {
|
||||
return (_has_bits_[0] & 0x00000002u) != 0;
|
||||
}
|
||||
inline void CommandPacket::set_has_value() {
|
||||
_has_bits_[0] |= 0x00000002u;
|
||||
}
|
||||
inline void CommandPacket::clear_has_value() {
|
||||
_has_bits_[0] &= ~0x00000002u;
|
||||
}
|
||||
inline void CommandPacket::clear_value() {
|
||||
value_ = false;
|
||||
clear_has_value();
|
||||
}
|
||||
inline bool CommandPacket::value() const {
|
||||
return value_;
|
||||
}
|
||||
inline void CommandPacket::set_value(bool value) {
|
||||
set_has_value();
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
|
||||
// @@protoc_insertion_point(namespace_scope)
|
||||
|
||||
|
@ -4,6 +4,9 @@ option optimize_for = LITE_RUNTIME;
|
||||
|
||||
package mozilla.layers.layerscope;
|
||||
|
||||
// ===============================
|
||||
// Server to Client messages
|
||||
// ===============================
|
||||
message FramePacket {
|
||||
optional uint64 value = 1;
|
||||
}
|
||||
@ -133,3 +136,17 @@ message Packet {
|
||||
optional LayersPacket layers = 5;
|
||||
optional MetaPacket meta = 6;
|
||||
}
|
||||
|
||||
|
||||
// ===============================
|
||||
// Client to Server messages
|
||||
// ===============================
|
||||
message CommandPacket {
|
||||
enum CmdType {
|
||||
NO_OP = 0;
|
||||
LAYERS_TREE = 1;
|
||||
LAYERS_BUFFER = 2;
|
||||
}
|
||||
required CmdType type = 1;
|
||||
optional bool value = 2;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user