1
/*********************************************************
2
* Copyright (C) 2010 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
*********************************************************/
22
* Implementation of common utility object for DnD/CP version 3 rpc object.
23
* It is shared by vmx and guest implementation. Some common utilities
25
* *packet marshalling/un-marshalling
27
* are implemented here.
31
#include "rpcV3Util.hpp"
36
#define LOG(level, msg) (Debug msg)
38
#define LOGLEVEL_MODULE dnd
39
#include "loglevel_user.h"
42
#include "dndClipboard.h"
54
RpcV3Util::RpcV3Util(void)
59
mSendBuf.buffer = NULL;
60
mRecvBuf.buffer = NULL;
61
DnD_TransportBufReset(&mSendBuf);
62
DnD_TransportBufReset(&mRecvBuf);
70
RpcV3Util::~RpcV3Util(void)
72
free(mSendBuf.buffer);
73
free(mRecvBuf.buffer);
78
* Initialize the RpcV3Util object. All owner should call this first before
79
* calling any other utility function.
81
* @param[in] rpc the owner of this utility object
82
* @param[in] msgType the type of message (DnD/CP/FT)
83
* @param[in] msgSrc source of the message (host/guest/controller)
87
RpcV3Util::Init(RpcBase *rpc)
95
* Serialize command, then send the message.
97
* @param[in] cmd version 3 command
99
* @return true on success, false otherwise.
103
RpcV3Util::SendMsg(uint32 cmd)
109
DnDMsg_SetCmd(&msg, cmd);
111
DnDMsg_Destroy(&msg);
118
* Serialize the clipboard item if there is one, then send the message to
121
* @param[in] cmd version 3 command
122
* @param[in] clip the clipboard item.
124
* @return true on success, false otherwise.
128
RpcV3Util::SendMsg(uint32 cmd,
129
const CPClipboard *clip)
138
/* Serialize clip and output into buf. */
139
if (!CPClipboard_Serialize(clip, &buf)) {
140
LOG(0, ("%s: CPClipboard_Serialize failed.\n", __FUNCTION__));
144
/* Construct msg with both cmd CP_HG_SET_CLIPBOARD and buf. */
145
DnDMsg_SetCmd(&msg, cmd);
146
if (!DnDMsg_AppendArg(&msg, DynBuf_Get(&buf), DynBuf_GetSize(&buf))) {
147
LOG(0, ("%s: DnDMsg_AppendData failed.\n", __FUNCTION__));
154
DynBuf_Destroy(&buf);
155
DnDMsg_Destroy(&msg);
161
* Serialize command with mouse position, and send the message.
163
* @param[in] cmd version 3 command
164
* @param[in] x mouse position x.
165
* @param[in] y mouse position y.
167
* @return true on success, false otherwise.
171
RpcV3Util::SendMsg(uint32 cmd,
181
DnDMsg_SetCmd(&msg, cmd);
183
if (!DnDMsg_AppendArg(&msg, &x, sizeof x) ||
184
!DnDMsg_AppendArg(&msg, &y, sizeof y)) {
185
LOG(0, ("%s: DnDMsg_AppendData failed.\n", __FUNCTION__));
192
DnDMsg_Destroy(&msg);
198
* Serialize and send the message.
200
* @param[in] msg the message to be serialized and sent.
202
* @return true on success, false otherwise.
206
RpcV3Util::SendMsg(const DnDMsg *msg)
213
/* Serialize msg and output to buf. */
214
if (!DnDMsg_Serialize((DnDMsg *)msg, &buf)) {
215
LOG(0, ("%s: DnDMsg_Serialize failed.\n", __FUNCTION__));
219
ret = SendMsg((uint8 *)DynBuf_Get(&buf), DynBuf_GetSize(&buf));
222
DynBuf_Destroy(&buf);
228
* Serialize the message and send it to destId.
231
* @param[in] binarySize
233
* @return true on success, false otherwise.
237
RpcV3Util::SendMsg(const uint8 *binary,
240
DnDTransportPacketHeader *packet = NULL;
244
if (binarySize > DNDMSG_MAX_ARGSZ) {
245
LOG(1, ("%s: message is too big, quit.\n", __FUNCTION__));
249
LOG(4, ("%s: got message, size %d.\n", __FUNCTION__, binarySize));
251
if (binarySize <= DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE) {
253
* It is a small size message, so it is not needed to buffer it. Just
254
* put message into a packet and send it.
256
packetSize = DnD_TransportMsgToPacket((uint8 *)binary, binarySize,
260
* It is a big size message. First buffer it and send it with multiple
263
if (mSendBuf.buffer) {
265
* There is a pending big size message. If there is no update time more than
266
* DND_MAX_TRANSPORT_LATENCY_TIME, remove old message and send new message.
267
* Otherwise ignore this message.
271
Hostinfo_GetTimeOfDay(&curTime);
273
if ((curTime - mSendBuf.lastUpdateTime) < DND_MAX_TRANSPORT_LATENCY_TIME) {
274
LOG(1, ("%s: got a big buffer, but there is another pending one, drop it\n",
279
DnD_TransportBufInit(&mSendBuf, (uint8 *)binary, binarySize, mSeqNum);
280
packetSize = DnD_TransportBufGetPacket(&mSendBuf, &packet);
283
/* Increase sequence number for next message. */
286
ret = mRpc->SendPacket(0, (const uint8 *)packet, packetSize);
295
* Callback from transport layer after received a packet from srcId.
297
* @param[in] srcId addressId where the packet is from
299
* @param[in] packetSize
303
RpcV3Util::OnRecvPacket(uint32 srcId,
307
DnDTransportPacketHeader *packetV3 = (DnDTransportPacketHeader *)packet;
309
if (packetSize <= 0 ||
310
packetSize != (packetV3->payloadSize + DND_TRANSPORT_PACKET_HEADER_SIZE) ||
311
packetSize > DND_MAX_TRANSPORT_PACKET_SIZE) {
312
LOG(0, ("%s: Received invalid data.\n", __FUNCTION__));
316
switch (packetV3->type) {
317
case DND_TRANSPORT_PACKET_TYPE_SINGLE:
318
if (packetV3->payloadSize != packetV3->totalSize) {
319
LOG(0, ("%s: received invalid packet.\n", __FUNCTION__));
322
/* This is a single packet. Forward to rpc layer for further processing. */
323
mRpc->HandleMsg(NULL, packetV3->payload, packetV3->payloadSize);
325
case DND_TRANSPORT_PACKET_TYPE_REQUEST:
327
/* Peer is asking for next packet. */
328
DnDTransportPacketHeader *replyPacket = NULL;
329
size_t replyPacketSize;
331
if (packetV3->payloadSize ||
332
packetV3->seqNum != mSendBuf.seqNum ||
333
packetV3->offset != mSendBuf.offset) {
334
LOG(0, ("%s: received packet does not match local buffer.\n", __FUNCTION__));
338
replyPacketSize = DnD_TransportBufGetPacket(&mSendBuf, &replyPacket);
340
if (!replyPacketSize) {
342
* Not needed to reset mSendBuf because DnD_TransportBufGetPacket already
345
LOG(0, ("%s: DnD_TransportBufGetPacket failed.\n", __FUNCTION__));
349
if (!mRpc->SendPacket(0, (const uint8 *)replyPacket, replyPacketSize) ||
350
mSendBuf.offset == mSendBuf.totalSize) {
351
/* Reset mSendBuf if whole buffer is sent or there is any error. */
352
DnD_TransportBufReset(&mSendBuf);
359
case DND_TRANSPORT_PACKET_TYPE_PAYLOAD:
360
/* Received next packet for big binary buffer. */
361
if (!DnD_TransportBufAppendPacket(&mRecvBuf, packetV3, packetSize)) {
362
LOG(0, ("%s: DnD_TransportBufAppendPacket failed.\n", __FUNCTION__));
366
if (mRecvBuf.offset == mRecvBuf.totalSize) {
368
* Received all packets for the messge, forward it to rpc layer for
369
* further processing.
371
mRpc->HandleMsg(NULL, mRecvBuf.buffer, mRecvBuf.totalSize);
372
DnD_TransportBufReset(&mRecvBuf);
374
/* Send request for next packet. */
375
DnDTransportPacketHeader *replyPacket = NULL;
376
size_t replyPacketSize;
378
replyPacketSize = DnD_TransportReqPacket(&mRecvBuf, &replyPacket);
380
if (!replyPacketSize) {
381
LOG(0, ("%s: DnD_TransportReqPacket failed.\n", __FUNCTION__));
385
if (!mRpc->SendPacket(0, (const uint8 *)replyPacket, replyPacketSize)) {
386
DnD_TransportBufReset(&mRecvBuf);
392
LOG(0, ("%s: unknown packet.\n", __FUNCTION__));