ostinato/rpc/rpcserver.cpp
Srivats P. f220482876 Added Google Protocol Buffers as the serialization format between client and server.
Initial Checkin. PB related code not yet complete
2008-08-09 03:22:13 +00:00

181 lines
4.5 KiB
C++

#include "pbhelper.h"
#include "rpcserver.h"
RpcServer::RpcServer()
{
server = NULL;
clientSock = NULL;
service = NULL;
isPending = false;
pendingMethodId = -1; // don't care as long as isPending is false
}
RpcServer::~RpcServer()
{
if (server)
delete server;
}
bool RpcServer::registerService(::google::protobuf::Service *service,
quint16 tcpPortNum)
{
this->service = service;
server = new QTcpServer();
connect(server, SIGNAL(newConnection()), this, SLOT(when_newConnection()));
if (!server->listen(QHostAddress::Any, tcpPortNum))
{
LogInt(tr("Unable to start the server: %1").arg(server->errorString()));
return false;
}
LogInt(tr("The server is running on %1:%2").arg(server->serverAddress().toString()).arg(server->serverPort()));
return true;
}
void RpcServer::done(::google::protobuf::Message *resp, PbRpcController *PbRpcController)
{
char msg[1024]; // FIXME: hardcoding
char *p = (char *)&msg;
int len;
qDebug("In RpcServer::done");
// TODO: check PbRpcController to see if method failed
if (PbRpcController->Failed())
{
qDebug("rpc failed");
goto _exit;
}
*((quint16*)(p+0)) = HTONS(PB_MSG_TYPE_RESPONSE); // type TODO:RESPONSE
*((quint16*)(p+2)) = HTONS(pendingMethodId); // method
*((quint16*)(p+6)) = HTONS(0); // rsvd
// SerialData is at offset 8
resp->SerializeToArray((void*) (p+8), sizeof(msg));
len = resp->ByteSize();
(*(quint16*)(p+4)) = HTONS(len); // len
qDebug("Server(%s): sending %d bytest to client encoding <%s>",
__FUNCTION__, len + 8, resp->DebugString().c_str());
BUFDUMP(msg, len + 8);
clientSock->write(msg, len + 8);
_exit:
delete PbRpcController;
isPending = false;
}
void RpcServer::when_newConnection()
{
if (clientSock)
{
QTcpSocket *sock;
LogInt(tr("already connected, no new connections will be accepted\n"));
// Accept and close connection
// TODO: Send reason msg to client
sock = server->nextPendingConnection();
sock->disconnectFromHost();
sock->deleteLater();
goto _exit;
}
clientSock = server->nextPendingConnection();
LogInt(tr("accepting new connection from %1:%2").arg(clientSock->peerAddress().toString()).arg(clientSock->peerPort()));
connect(clientSock, SIGNAL(readyRead()),
this, SLOT(when_dataAvail()));
connect(clientSock, SIGNAL(disconnected()),
this, SLOT(when_disconnected()));
connect(clientSock, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(when_error(QAbstractSocket::SocketError)));
_exit:
return;
}
void RpcServer::when_disconnected()
{
LogInt(tr("connection closed from %1:%2").arg(clientSock->peerAddress().toString()).arg(clientSock->peerPort()));
clientSock->deleteLater();
clientSock = NULL;
}
void RpcServer::when_error(QAbstractSocket::SocketError socketError)
{
LogInt(clientSock->errorString());
}
void RpcServer::when_dataAvail()
{
char msg[1024]; // FIXME: hardcoding;
int msgLen;
char *p = (char*) &msg;
quint16 type, method, len, rsvd;
const ::google::protobuf::MethodDescriptor *methodDesc;
::google::protobuf::Message *req, *resp;
PbRpcController *controller;
msgLen = clientSock->read(msg, sizeof(msg));
LogInt(QString(QByteArray(msg, msgLen).toHex()));
qDebug("Server %s: rcvd %d bytes", __FUNCTION__, msgLen);
BUFDUMP(msg, msgLen);
type = NTOHS(GET16(p+0));
qDebug("GET16 = %d/%d, type = %d", GET16(p+0), NTOHS(GET16(p+0)), type);
method = NTOHS(GET16(p+2));
len = NTOHS(GET16(p+4));
rsvd = NTOHS(GET16(p+6));
if (type != PB_MSG_TYPE_REQUEST)
{
qDebug("server(%s): unexpected msg type %d (expected %d)", __FUNCTION__,
type, PB_MSG_TYPE_REQUEST);
goto _error_exit;
}
methodDesc = service->GetDescriptor()->method(method);
if (!methodDesc)
{
qDebug("server(%s): invalid method id %d", __FUNCTION__, method);
goto _error_exit; // TODO: Return Error to client
}
if (isPending)
{
qDebug("server(%s): rpc pending, try again", __FUNCTION__);
goto _error_exit; // TODO: Return Error to client
}
pendingMethodId = method;
isPending = true;
req = service->GetRequestPrototype(methodDesc).New();
resp = service->GetResponsePrototype(methodDesc).New();
// Serialized data starts from offset 8
req->ParseFromArray((void*) (msg+8), len);
controller = new PbRpcController;
service->CallMethod(methodDesc, controller, req, resp,
NewCallback(this, &RpcServer::done, resp, controller));
return;
_error_exit:
qDebug("server(%s): discarding msg from client", __FUNCTION__);
return;
}