RPC now uses stream instead of an array for protobuf parsing and serialization. This change removes the limit on the byte size of a protobuf.
Because we are now using a new protobuf API - ParseFromBoundedZeroCopyStream(), the protobuf version has to be >= 2.2.0 Fixes issue 14
This commit is contained in:
parent
c5fbceebb4
commit
90fda499dd
@ -5,7 +5,6 @@ win32:RC_FILE = ostinato.rc
|
|||||||
macx:ICON = icons/logo.icns
|
macx:ICON = icons/logo.icns
|
||||||
QT += network script
|
QT += network script
|
||||||
INCLUDEPATH += "../rpc/" "../common/"
|
INCLUDEPATH += "../rpc/" "../common/"
|
||||||
LIBS += -lprotobuf
|
|
||||||
win32 {
|
win32 {
|
||||||
CONFIG(debug, debug|release) {
|
CONFIG(debug, debug|release) {
|
||||||
LIBS += -L"../common/debug" -lostproto
|
LIBS += -L"../common/debug" -lostproto
|
||||||
@ -25,6 +24,7 @@ win32 {
|
|||||||
LIBS += -L"../rpc" -lpbrpc
|
LIBS += -L"../rpc" -lpbrpc
|
||||||
POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a"
|
POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a"
|
||||||
}
|
}
|
||||||
|
LIBS += -lprotobuf
|
||||||
RESOURCES += ostinato.qrc
|
RESOURCES += ostinato.qrc
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
dumpview.h \
|
dumpview.h \
|
||||||
|
42
rpc/pbqtio.h
Normal file
42
rpc/pbqtio.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef _PBQTIO_H
|
||||||
|
#define _PBQTIO_H
|
||||||
|
|
||||||
|
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||||
|
|
||||||
|
class PbQtInputStream : public google::protobuf::io::CopyingInputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PbQtInputStream(QIODevice *dev)
|
||||||
|
: dev_(dev) {};
|
||||||
|
int Read(void *buffer, int size) {
|
||||||
|
_top:
|
||||||
|
if (dev_->bytesAvailable())
|
||||||
|
return dev_->read(static_cast<char*>(buffer), size);
|
||||||
|
else
|
||||||
|
if (dev_->waitForReadyRead(-1))
|
||||||
|
goto _top;
|
||||||
|
else
|
||||||
|
return -1; //return dev_->atEnd() ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QIODevice *dev_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PbQtOutputStream : public google::protobuf::io::CopyingOutputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PbQtOutputStream(QIODevice *dev)
|
||||||
|
: dev_(dev) {};
|
||||||
|
bool Write(const void *buffer, int size) {
|
||||||
|
if (dev_->write(static_cast<const char*>(buffer), size) == size)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QIODevice *dev_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -3,5 +3,5 @@ CONFIG += qt staticlib
|
|||||||
QT += network
|
QT += network
|
||||||
DEFINES += HAVE_REMOTE
|
DEFINES += HAVE_REMOTE
|
||||||
LIBS += -lprotobuf
|
LIBS += -lprotobuf
|
||||||
HEADERS += rpcserver.h pbrpccontroller.h pbrpcchannel.h
|
HEADERS += rpcserver.h pbrpccontroller.h pbrpcchannel.h pbqtio.h
|
||||||
SOURCES += rpcserver.cpp pbrpcchannel.cpp
|
SOURCES += rpcserver.cpp pbrpcchannel.cpp
|
||||||
|
@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pbrpcchannel.h"
|
#include "pbrpcchannel.h"
|
||||||
|
#include "pbqtio.h"
|
||||||
|
|
||||||
#include <qendian.h>
|
#include <qendian.h>
|
||||||
|
|
||||||
@ -34,6 +35,13 @@ PbRpcChannel::PbRpcChannel(QHostAddress ip, quint16 port)
|
|||||||
mServerPort = port;
|
mServerPort = port;
|
||||||
mpSocket = new QTcpSocket(this);
|
mpSocket = new QTcpSocket(this);
|
||||||
|
|
||||||
|
inStream = new google::protobuf::io::CopyingInputStreamAdaptor(
|
||||||
|
new PbQtInputStream(mpSocket));
|
||||||
|
inStream->SetOwnsCopyingStream(true);
|
||||||
|
outStream = new google::protobuf::io::CopyingOutputStreamAdaptor(
|
||||||
|
new PbQtOutputStream(mpSocket));
|
||||||
|
outStream->SetOwnsCopyingStream(true);
|
||||||
|
|
||||||
// FIXME: Not quite sure why this ain't working!
|
// FIXME: Not quite sure why this ain't working!
|
||||||
// QMetaObject::connectSlotsByName(this);
|
// QMetaObject::connectSlotsByName(this);
|
||||||
|
|
||||||
@ -53,6 +61,8 @@ PbRpcChannel::PbRpcChannel(QHostAddress ip, quint16 port)
|
|||||||
|
|
||||||
PbRpcChannel::~PbRpcChannel()
|
PbRpcChannel::~PbRpcChannel()
|
||||||
{
|
{
|
||||||
|
delete inStream;
|
||||||
|
delete outStream;
|
||||||
delete mpSocket;
|
delete mpSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +94,7 @@ void PbRpcChannel::CallMethod(
|
|||||||
::google::protobuf::Message *response,
|
::google::protobuf::Message *response,
|
||||||
::google::protobuf::Closure* done)
|
::google::protobuf::Closure* done)
|
||||||
{
|
{
|
||||||
char msgBuf[MSGBUF_SIZE];
|
char msgBuf[PB_HDR_SIZE];
|
||||||
char* const msg = &msgBuf[0];
|
char* const msg = &msgBuf[0];
|
||||||
int len;
|
int len;
|
||||||
bool ret;
|
bool ret;
|
||||||
@ -128,9 +138,6 @@ void PbRpcChannel::CallMethod(
|
|||||||
this->response=response;
|
this->response=response;
|
||||||
isPending = true;
|
isPending = true;
|
||||||
|
|
||||||
ret = req->SerializeToArray((void*)(msg+PB_HDR_SIZE), sizeof(msgBuf)-PB_HDR_SIZE);
|
|
||||||
Q_ASSERT(ret == true);
|
|
||||||
|
|
||||||
len = req->ByteSize();
|
len = req->ByteSize();
|
||||||
*((quint16*)(msg+0)) = qToBigEndian(quint16(PB_MSG_TYPE_REQUEST)); // type
|
*((quint16*)(msg+0)) = qToBigEndian(quint16(PB_MSG_TYPE_REQUEST)); // type
|
||||||
*((quint16*)(msg+2)) = qToBigEndian(quint16(method->index())); // method id
|
*((quint16*)(msg+2)) = qToBigEndian(quint16(method->index())); // method id
|
||||||
@ -141,15 +148,18 @@ void PbRpcChannel::CallMethod(
|
|||||||
{
|
{
|
||||||
qDebug("client(%s) sending %d bytes encoding <%s>", __FUNCTION__,
|
qDebug("client(%s) sending %d bytes encoding <%s>", __FUNCTION__,
|
||||||
PB_HDR_SIZE + len, req->DebugString().c_str());
|
PB_HDR_SIZE + len, req->DebugString().c_str());
|
||||||
BUFDUMP(msg, PB_HDR_SIZE + len);
|
BUFDUMP(msg, PB_HDR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpSocket->write(msg, PB_HDR_SIZE + len);
|
mpSocket->write(msg, PB_HDR_SIZE);
|
||||||
|
ret = req->SerializeToZeroCopyStream(outStream);
|
||||||
|
Q_ASSERT(ret == true);
|
||||||
|
outStream->Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PbRpcChannel::on_mpSocket_readyRead()
|
void PbRpcChannel::on_mpSocket_readyRead()
|
||||||
{
|
{
|
||||||
uchar msg[MSGBUF_SIZE];
|
uchar msg[PB_HDR_SIZE];
|
||||||
uchar *p = (uchar*) &msg;
|
uchar *p = (uchar*) &msg;
|
||||||
int msgLen;
|
int msgLen;
|
||||||
static bool parsing = false;
|
static bool parsing = false;
|
||||||
@ -210,31 +220,20 @@ void PbRpcChannel::on_mpSocket_readyRead()
|
|||||||
if (!isPending)
|
if (!isPending)
|
||||||
{
|
{
|
||||||
qDebug("not waiting for response");
|
qDebug("not waiting for response");
|
||||||
goto _error_exit;
|
goto _error_exit2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pendingMethodId != method)
|
if (pendingMethodId != method)
|
||||||
{
|
{
|
||||||
qDebug("invalid method id %d (expected = %d)", method,
|
qDebug("invalid method id %d (expected = %d)", method,
|
||||||
pendingMethodId);
|
pendingMethodId);
|
||||||
goto _error_exit;
|
goto _error_exit2;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PB_MSG_TYPE_RESPONSE:
|
case PB_MSG_TYPE_RESPONSE:
|
||||||
// Wait till we have the entire message
|
|
||||||
if (mpSocket->bytesAvailable() < len)
|
|
||||||
{
|
|
||||||
qDebug("client: not enough data available for a complete msg");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
msgLen = mpSocket->read((char*)msg, sizeof(msg));
|
|
||||||
|
|
||||||
Q_ASSERT((unsigned) msgLen == len);
|
|
||||||
|
|
||||||
//qDebug("client(%s) rcvd %d bytes", __FUNCTION__, msgLen);
|
//qDebug("client(%s) rcvd %d bytes", __FUNCTION__, msgLen);
|
||||||
//BUFDUMP(msg, msgLen);
|
//BUFDUMP(msg, msgLen);
|
||||||
|
|
||||||
@ -251,7 +250,8 @@ void PbRpcChannel::on_mpSocket_readyRead()
|
|||||||
goto _error_exit;
|
goto _error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
response->ParseFromArray((void*) msg, len);
|
if (len)
|
||||||
|
response->ParseFromBoundedZeroCopyStream(inStream, len);
|
||||||
|
|
||||||
// Avoid printing stats
|
// Avoid printing stats
|
||||||
if (method != 13)
|
if (method != 13)
|
||||||
@ -295,6 +295,8 @@ void PbRpcChannel::on_mpSocket_readyRead()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_error_exit:
|
_error_exit:
|
||||||
|
inStream->Skip(len);
|
||||||
|
_error_exit2:
|
||||||
parsing = false;
|
parsing = false;
|
||||||
qDebug("client(%s) discarding received msg", __FUNCTION__);
|
qDebug("client(%s) discarding received msg", __FUNCTION__);
|
||||||
return;
|
return;
|
||||||
|
@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
|
||||||
|
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||||
#include <google/protobuf/message.h>
|
#include <google/protobuf/message.h>
|
||||||
#include <google/protobuf/descriptor.h>
|
#include <google/protobuf/descriptor.h>
|
||||||
#include <google/protobuf/service.h>
|
#include <google/protobuf/service.h>
|
||||||
@ -64,6 +65,9 @@ class PbRpcChannel : public QObject, public ::google::protobuf::RpcChannel
|
|||||||
quint16 mServerPort;
|
quint16 mServerPort;
|
||||||
QTcpSocket *mpSocket;
|
QTcpSocket *mpSocket;
|
||||||
|
|
||||||
|
::google::protobuf::io::CopyingInputStreamAdaptor *inStream;
|
||||||
|
::google::protobuf::io::CopyingOutputStreamAdaptor *outStream;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PbRpcChannel(QHostAddress ip, quint16 port);
|
PbRpcChannel(QHostAddress ip, quint16 port);
|
||||||
~PbRpcChannel();
|
~PbRpcChannel();
|
||||||
|
@ -36,6 +36,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#define PB_MSG_TYPE_RESPONSE 2
|
#define PB_MSG_TYPE_RESPONSE 2
|
||||||
#define PB_MSG_TYPE_BINBLOB 3
|
#define PB_MSG_TYPE_BINBLOB 3
|
||||||
|
|
||||||
#define MSGBUF_SIZE 4096
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
//#include "pbhelper.h"
|
//#include "pbhelper.h"
|
||||||
#include "rpcserver.h"
|
#include "rpcserver.h"
|
||||||
|
#include "pbqtio.h"
|
||||||
|
|
||||||
#include <qendian.h>
|
#include <qendian.h>
|
||||||
|
|
||||||
@ -29,6 +30,9 @@ RpcServer::RpcServer()
|
|||||||
|
|
||||||
service = NULL;
|
service = NULL;
|
||||||
|
|
||||||
|
inStream = NULL;
|
||||||
|
outStream = NULL;
|
||||||
|
|
||||||
isPending = false;
|
isPending = false;
|
||||||
pendingMethodId = -1; // don't care as long as isPending is false
|
pendingMethodId = -1; // don't care as long as isPending is false
|
||||||
}
|
}
|
||||||
@ -71,7 +75,7 @@ void RpcServer::done(PbRpcController *controller)
|
|||||||
{
|
{
|
||||||
google::protobuf::Message *response = controller->response();
|
google::protobuf::Message *response = controller->response();
|
||||||
QIODevice *blob;
|
QIODevice *blob;
|
||||||
char msgBuf[MSGBUF_SIZE];
|
char msgBuf[PB_HDR_SIZE];
|
||||||
char* const msg = &msgBuf[0];
|
char* const msg = &msgBuf[0];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
@ -116,8 +120,6 @@ void RpcServer::done(PbRpcController *controller)
|
|||||||
goto _exit;
|
goto _exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
response->SerializeToArray((void*)(msg+PB_HDR_SIZE), sizeof(msgBuf)-PB_HDR_SIZE);
|
|
||||||
|
|
||||||
len = response->ByteSize();
|
len = response->ByteSize();
|
||||||
|
|
||||||
*((quint16*)(msg+0)) = qToBigEndian(quint16(PB_MSG_TYPE_RESPONSE)); // type
|
*((quint16*)(msg+0)) = qToBigEndian(quint16(PB_MSG_TYPE_RESPONSE)); // type
|
||||||
@ -132,7 +134,9 @@ void RpcServer::done(PbRpcController *controller)
|
|||||||
//BUFDUMP(msg, len + 8);
|
//BUFDUMP(msg, len + 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
clientSock->write(msg, PB_HDR_SIZE + len);
|
clientSock->write(msg, PB_HDR_SIZE);
|
||||||
|
response->SerializeToZeroCopyStream(outStream);
|
||||||
|
outStream->Flush();
|
||||||
|
|
||||||
_exit:
|
_exit:
|
||||||
delete controller;
|
delete controller;
|
||||||
@ -159,6 +163,12 @@ void RpcServer::when_newConnection()
|
|||||||
qDebug("accepting new connection from %s: %d",
|
qDebug("accepting new connection from %s: %d",
|
||||||
clientSock->peerAddress().toString().toAscii().constData(),
|
clientSock->peerAddress().toString().toAscii().constData(),
|
||||||
clientSock->peerPort());
|
clientSock->peerPort());
|
||||||
|
inStream = new google::protobuf::io::CopyingInputStreamAdaptor(
|
||||||
|
new PbQtInputStream(clientSock));
|
||||||
|
inStream->SetOwnsCopyingStream(true);
|
||||||
|
outStream = new google::protobuf::io::CopyingOutputStreamAdaptor(
|
||||||
|
new PbQtOutputStream(clientSock));
|
||||||
|
outStream->SetOwnsCopyingStream(true);
|
||||||
|
|
||||||
connect(clientSock, SIGNAL(readyRead()),
|
connect(clientSock, SIGNAL(readyRead()),
|
||||||
this, SLOT(when_dataAvail()));
|
this, SLOT(when_dataAvail()));
|
||||||
@ -177,6 +187,9 @@ void RpcServer::when_disconnected()
|
|||||||
clientSock->peerAddress().toString().toAscii().constData(),
|
clientSock->peerAddress().toString().toAscii().constData(),
|
||||||
clientSock->peerPort());
|
clientSock->peerPort());
|
||||||
|
|
||||||
|
delete inStream;
|
||||||
|
delete outStream;
|
||||||
|
|
||||||
clientSock->deleteLater();
|
clientSock->deleteLater();
|
||||||
clientSock = NULL;
|
clientSock = NULL;
|
||||||
}
|
}
|
||||||
@ -189,7 +202,7 @@ void RpcServer::when_error(QAbstractSocket::SocketError socketError)
|
|||||||
|
|
||||||
void RpcServer::when_dataAvail()
|
void RpcServer::when_dataAvail()
|
||||||
{
|
{
|
||||||
uchar msg[MSGBUF_SIZE];
|
uchar msg[PB_HDR_SIZE];
|
||||||
int msgLen;
|
int msgLen;
|
||||||
static bool parsing = false;
|
static bool parsing = false;
|
||||||
static quint16 type, method;
|
static quint16 type, method;
|
||||||
@ -215,12 +228,6 @@ void RpcServer::when_dataAvail()
|
|||||||
parsing = true;
|
parsing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientSock->bytesAvailable() < len)
|
|
||||||
return;
|
|
||||||
|
|
||||||
msgLen = clientSock->read((char*)msg, sizeof(msg));
|
|
||||||
Q_ASSERT((unsigned) msgLen == len);
|
|
||||||
|
|
||||||
if (type != PB_MSG_TYPE_REQUEST)
|
if (type != PB_MSG_TYPE_REQUEST)
|
||||||
{
|
{
|
||||||
qDebug("server(%s): unexpected msg type %d (expected %d)", __FUNCTION__,
|
qDebug("server(%s): unexpected msg type %d (expected %d)", __FUNCTION__,
|
||||||
@ -247,7 +254,9 @@ void RpcServer::when_dataAvail()
|
|||||||
req = service->GetRequestPrototype(methodDesc).New();
|
req = service->GetRequestPrototype(methodDesc).New();
|
||||||
resp = service->GetResponsePrototype(methodDesc).New();
|
resp = service->GetResponsePrototype(methodDesc).New();
|
||||||
|
|
||||||
req->ParseFromArray((void*)msg, len);
|
if (len)
|
||||||
|
req->ParseFromBoundedZeroCopyStream(inStream, len);
|
||||||
|
|
||||||
if (!req->IsInitialized())
|
if (!req->IsInitialized())
|
||||||
{
|
{
|
||||||
qWarning("Missing required fields in request");
|
qWarning("Missing required fields in request");
|
||||||
@ -256,7 +265,7 @@ void RpcServer::when_dataAvail()
|
|||||||
delete req;
|
delete req;
|
||||||
delete resp;
|
delete resp;
|
||||||
|
|
||||||
goto _error_exit;
|
goto _error_exit2;
|
||||||
}
|
}
|
||||||
//qDebug("Server(%s): successfully parsed as <%s>", __FUNCTION__,
|
//qDebug("Server(%s): successfully parsed as <%s>", __FUNCTION__,
|
||||||
//resp->DebugString().c_str());
|
//resp->DebugString().c_str());
|
||||||
@ -273,6 +282,8 @@ void RpcServer::when_dataAvail()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_error_exit:
|
_error_exit:
|
||||||
|
inStream->Skip(len);
|
||||||
|
_error_exit2:
|
||||||
parsing = false;
|
parsing = false;
|
||||||
qDebug("server(%s): discarding msg from client", __FUNCTION__);
|
qDebug("server(%s): discarding msg from client", __FUNCTION__);
|
||||||
return;
|
return;
|
||||||
|
@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include <google/protobuf/message.h>
|
#include <google/protobuf/message.h>
|
||||||
#include <google/protobuf/descriptor.h>
|
#include <google/protobuf/descriptor.h>
|
||||||
#include <google/protobuf/service.h>
|
#include <google/protobuf/service.h>
|
||||||
|
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||||
|
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
@ -39,6 +40,8 @@ class RpcServer : public QObject
|
|||||||
QTcpSocket *clientSock;
|
QTcpSocket *clientSock;
|
||||||
|
|
||||||
::google::protobuf::Service *service;
|
::google::protobuf::Service *service;
|
||||||
|
::google::protobuf::io::CopyingInputStreamAdaptor *inStream;
|
||||||
|
::google::protobuf::io::CopyingOutputStreamAdaptor *outStream;
|
||||||
|
|
||||||
bool isPending;
|
bool isPending;
|
||||||
int pendingMethodId;
|
int pendingMethodId;
|
||||||
|
Loading…
Reference in New Issue
Block a user