1
/*********************************************************
2
* Copyright (C) 2007 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
20
* dndTransportGuestRpc.cc --
22
* GuestRpc implementation of the dndTransport interface.
24
* A multiple packet transport protocol is implemented in this layer to
25
* support big buffer transfer. With the support, message size limit is
26
* improved from 64K to 4M (theoratically can be 4G).
28
* There are 3 different types of packet. If a message is smaller than
29
* 64K, it will be sent with type DND_TRANSPORT_PACKET_TYPE_SINGLE. If
30
* it is bigger than 64K, initial 64K will be first sent with
31
* DND_TRANSPORT_PACKET_TYPE_PAYLOAD. After received the packet, the
32
* receiver should reply with DND_TRANSPORT_PACKET_TYPE_REQUEST, then
33
* next 64K will be sent.
35
* This is a temporary solution before VICF is available. To simplify
36
* the implementation, there are some limitations:
37
* 1. Any time for any transport class, there is only one pending
38
* big buffer for each direction. Any following big size message will
39
* be dropped before the pending transfer is done.Small message (<64K)
40
* can be sent at any time.
41
* 2. Caller can not cancel any pending big buffer sending and
43
* 3. Pending big buffer will be dropped if there is any error.
47
#include <sigc++/hide.h>
49
#include "dndTransportGuestRpc.hh"
62
*-----------------------------------------------------------------------------
69
* TRUE if success, FALSE otherwise.
74
*-----------------------------------------------------------------------------
78
RecvMsgCB(char const **result, // OUT
79
size_t *resultLen, // OUT
80
const char *name, // IN
81
const char *args, // IN
82
size_t argsSize, // IN: Size of args
83
void *clientData) // IN
85
DnDTransportGuestRpc *transport = (DnDTransportGuestRpc *)clientData;
88
/* '- 1' is to ignore empty space between command and args. */
89
if ((argsSize - 1) <= 0) {
90
Debug("%s: invalid argsSize\n", __FUNCTION__);
91
return RpcIn_SetRetVals(result, resultLen, "invalid arg size", FALSE);
93
transport->RecvMsg((DnDTransportPacketHeader *)(args + 1), argsSize - 1);
94
return RpcIn_SetRetVals(result, resultLen, "", TRUE);
99
*-----------------------------------------------------------------------------
101
* DnDTransportGuestRpc::DnDTransportGuestRpc --
103
* Constructor of DnDTransportGuestRpc class.
111
*-----------------------------------------------------------------------------
114
DnDTransportGuestRpc::DnDTransportGuestRpc(struct RpcIn *rpcIn, // IN
115
const char *rpcCmd) // IN
121
RpcIn_RegisterCallback(rpcIn, rpcCmd, RecvMsgCB, this);
122
mRpcCmd = Util_SafeStrdup(rpcCmd);
124
mSendBuf.buffer = NULL;
125
mRecvBuf.buffer = NULL;
126
DnD_TransportBufReset(&mSendBuf);
127
DnD_TransportBufReset(&mRecvBuf);
133
*----------------------------------------------------------------------
135
* DnDTransportGuestRpc::~DnDTransportGuestRpc --
137
* Destructor of DnDTransportGuestRpc.
145
*----------------------------------------------------------------------
148
DnDTransportGuestRpc::~DnDTransportGuestRpc(void)
150
RpcIn_UnregisterCallback(mRpcIn, mRpcCmd);
152
free(mSendBuf.buffer);
153
free(mRecvBuf.buffer);
158
*-----------------------------------------------------------------------------
160
* DnDTransportGuestRpc::SendMsg --
162
* Sends msg to the VMX.
165
* TRUE if success, FALSE otherwise.
170
*-----------------------------------------------------------------------------
174
DnDTransportGuestRpc::SendMsg(uint8 *msg, // IN
177
DnDTransportPacketHeader *packet = NULL;
181
if (length > DNDMSG_MAX_ARGSZ) {
182
Debug("%s: message is too big, quit.\n", __FUNCTION__);
186
Debug("%s: got message, size %"FMTSZ"u\n", __FUNCTION__, length);
188
if (length <= DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE) {
190
* It is a small size message, so it is not needed to buffer it in the transport
191
* layer. Just put message into a packet and send it.
193
packetSize = DnD_TransportMsgToPacket(msg, length, mSeqNum, &packet);
196
* It is a big size message. First buffer it in the transport layer and send
197
* it with multiple packets.
199
if (mSendBuf.buffer) {
201
* There is a pending big size message. If there is no update time more than
202
* DND_MAX_TRANSPORT_LATENCY_TIME, remove old message and send new message.
203
* Otherwise ignore this message.
205
* XXX This transport implementation is just a temporary solution before VICF
206
* is available. So any time there is only one pending big buffer. Any other
207
* big message during this time will be dropped. Current pending buffer will
208
* also be dropped if there is any error. Later on VICF should provide a
209
* better transportation.
213
Hostinfo_GetTimeOfDay(&curTime);
215
if ((curTime - mSendBuf.lastUpdateTime) < DND_MAX_TRANSPORT_LATENCY_TIME) {
216
Debug("%s: got a big buffer, but there is already a pending one, quitting\n",
221
DnD_TransportBufInit(&mSendBuf, msg, length, mSeqNum);
222
packetSize = DnD_TransportBufGetPacket(&mSendBuf, &packet);
227
ret = SendPacket((uint8 *)packet, packetSize);
235
*-----------------------------------------------------------------------------
237
* DnDTransportGuestRpc::SendPacket --
239
* Sends packet to the VMX.
242
* TRUE if success, FALSE otherwise.
247
*-----------------------------------------------------------------------------
251
DnDTransportGuestRpc::SendPacket(uint8 *packet, // IN
252
size_t packetSize) // IN
256
size_t nrWritten = 0;
259
if (packetSize == 0 || packetSize > DND_MAX_TRANSPORT_PACKET_SIZE) {
260
Debug("%s: invalid packet\n", __FUNCTION__);
264
rpcSize = strlen(mRpcCmd) + 1 + packetSize;
265
rpc = (char *)Util_SafeMalloc(rpcSize);
266
nrWritten = Str_Sprintf(rpc, rpcSize, "%s ", mRpcCmd);
267
ASSERT(nrWritten + packetSize <= rpcSize);
268
memcpy(rpc + nrWritten, packet, packetSize);
270
ret = (TRUE == RpcOut_SendOneRaw(rpc, rpcSize, NULL, NULL));
273
Debug("%s: failed to send msg to host\n", __FUNCTION__);
282
*-----------------------------------------------------------------------------
284
* DnDTransportGuestRpc::RecvMsg --
286
* Receives packet from VMX.
294
*-----------------------------------------------------------------------------
298
DnDTransportGuestRpc::RecvMsg(DnDTransportPacketHeader *packet, // IN
299
size_t packetSize) // IN
301
if (packetSize <= 0 ||
302
packetSize != (packet->payloadSize + DND_TRANSPORT_PACKET_HEADER_SIZE) ||
303
packetSize > DND_MAX_TRANSPORT_PACKET_SIZE) {
304
Debug("%s: Received invalid data.\n", __FUNCTION__);
308
Debug("%s: received data, size %"FMTSZ"u.\n", __FUNCTION__, packetSize);
310
switch (packet->type) {
311
case DND_TRANSPORT_PACKET_TYPE_SINGLE:
312
if (packet->payloadSize != packet->totalSize) {
313
Debug("%s: received invalid packet.\n", __FUNCTION__);
316
recvMsgChanged.emit(packet->payload,
317
packet->payloadSize);
319
case DND_TRANSPORT_PACKET_TYPE_REQUEST:
321
DnDTransportPacketHeader *replyPacket = NULL;
322
size_t replyPacketSize;
324
/* Validate received packet. */
325
if (packet->payloadSize ||
326
packet->seqNum != mSendBuf.seqNum ||
327
packet->offset != mSendBuf.offset) {
328
Debug("%s: received packet does not match local buffer.\n", __FUNCTION__);
332
replyPacketSize = DnD_TransportBufGetPacket(&mSendBuf, &replyPacket);
334
if (!replyPacketSize) {
336
* Not needed to reset mSendBuf because DnD_TransportBufGetPacket already
339
Debug("%s: DnD_TransportBufGetPacket failed.\n", __FUNCTION__);
343
if (!SendPacket((uint8 *)replyPacket, replyPacketSize) ||
344
mSendBuf.offset == mSendBuf.totalSize) {
345
/* Reset mSendBuf if whole buffer is sent or there is any error. */
346
DnD_TransportBufReset(&mSendBuf);
353
case DND_TRANSPORT_PACKET_TYPE_PAYLOAD:
354
if (!DnD_TransportBufAppendPacket(&mRecvBuf, packet, packetSize)) {
355
Debug("%s: DnD_TransportBufAppendPacket failed.\n", __FUNCTION__);
359
if (mRecvBuf.offset == mRecvBuf.totalSize) {
360
/* Received all packets for the messge. */
361
recvMsgChanged.emit(mRecvBuf.buffer, mRecvBuf.totalSize);
362
DnD_TransportBufReset(&mRecvBuf);
364
/* Send request for next packet. */
365
DnDTransportPacketHeader *replyPacket = NULL;
366
size_t replyPacketSize;
368
replyPacketSize = DnD_TransportReqPacket(&mRecvBuf, &replyPacket);
370
if (!replyPacketSize) {
371
Debug("%s: DnD_TransportReqPacket failed.\n", __FUNCTION__);
375
if (!SendPacket((uint8 *)replyPacket, replyPacketSize)) {
376
DnD_TransportBufReset(&mRecvBuf);
382
Debug("%s: unknown packet.\n", __FUNCTION__);