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
*********************************************************/
20
* hgfsChannelGuest.c --
22
* Channel abstraction for the HGFS server.
27
#include "vm_assert.h"
28
#include "vm_atomic.h"
30
#if defined(VMTOOLS_USE_GLIB)
31
#define G_LOG_DOMAIN "hgfsd"
33
#define Warning g_warning
34
#include "vmware/tools/guestrpc.h"
35
#include "vmware/tools/utils.h"
40
#include "hgfsChannelGuestInt.h"
41
#include "hgfsServer.h"
42
#include "hgfsServerManager.h"
45
* HGFS server connection channel and state object usage.
47
* Currently, all plugins can share this same HGFS server channel and state.
48
* This allows us to use a common channel so it is only initialized
49
* once, by the first loaded plugin which requires an HGFS channel, and torn
50
* down when the final plugin that uses the HGFS server is unloaded.
52
* Currently, the plugins are loaded (and unloaded) in any particular order,
53
* and those operations are serialized. (For example the HGFS server plugin
54
* maybe the first plugin loaded that uses this channel, but is not the final
55
* plugin to be unloaded that uses the channel. This also may change in the
56
* future, so no dependencies can be made on order of loading and unloading
58
* Furthermore, multiple plugins use the HGFS channel and server and some plugins
59
* have multiple connections. Some plugins also create and teardown connections
60
* during general mutlithreaded operation of the tools processes.
62
* In order to support the above, we must track how many users of the shared
63
* connection there are. This allows us to tear down the shared connection
64
* when the final plugin that is using it is unloaded, and when no
65
* channels are in use the HGFS server state can be torn down.
69
* The HGFS server state.
71
* This object is initiliazed once only and is shared across all
72
* connections, shared or private.
73
* Each new channel connection will reference the server and so the HGFS
74
* server is initialized when the first new channel is being created. Each
75
* new channel just increments the reference of server state object.
76
* When the final channel is torn down the final HGFS server reference is
77
* also removed and the HGFS server exit is called and this object is torn down.
79
typedef struct HgfsChannelServerData {
80
HgfsServerSessionCallbacks *serverCBTable; /* HGFS server entry points. */
81
Atomic_uint32 refCount; /* Server data reference count. */
82
} HgfsChannelServerData;
85
* Transport channels context.
87
* Multiple callers share this same channel currently as only one
88
* transport channel is required. Therefore, the channel is referenced
89
* for each client that it is returned to (a usage count).
91
typedef struct HgfsChannelData {
92
const char *name; /* Channel name. */
93
HgfsGuestChannelCBTable *ops; /* Channel operations. */
94
uint32 state; /* Channel state (see flags below). */
95
struct HgfsGuestConn *connection; /* Opaque server connection */
96
HgfsChannelServerData *serverInfo; /* HGFS server entry points. */
97
Atomic_uint32 refCount; /* Channel reference count. */
100
#define HGFS_CHANNEL_STATE_INIT (1 << 0)
101
#define HGFS_CHANNEL_STATE_CBINIT (1 << 1)
103
/* Static channel registration - assumes only one for now. */
104
static HgfsChannelData gHgfsChannels[] = {
105
{ "guest", &gGuestBackdoorOps, 0, NULL, NULL, {0} },
108
/* HGFS server info state. Referenced by each separate channel that uses it. */
109
static HgfsChannelServerData gHgfsChannelServerInfo = { NULL, {0} };
111
static void HgfsChannelTeardownChannel(HgfsChannelData *channel);
112
static void HgfsChannelTeardownServer(HgfsChannelServerData *serverInfo);
113
static void HgfsChannelExitChannel(HgfsChannelData *channel);
117
*----------------------------------------------------------------------------
119
* HGFS SERVER DATA FUNCTIONS
121
*----------------------------------------------------------------------------
126
*----------------------------------------------------------------------------
128
* HgfsChannelGetServer --
130
* Increment the server data reference count.
133
* The value of the reference count before the increment.
138
*----------------------------------------------------------------------------
142
HgfsChannelGetServer(HgfsChannelServerData *serverInfo) // IN/OUT: ref count
144
ASSERT(NULL != serverInfo);
145
return Atomic_FetchAndInc(&serverInfo->refCount);
150
*----------------------------------------------------------------------------
152
* HgfsChannelPutServer --
154
* Decrement server data reference count.
156
* Teardown the server data object if removed the final reference.
164
*----------------------------------------------------------------------------
168
HgfsChannelPutServer(HgfsChannelServerData *serverInfo) // IN/OUT: ref count
170
ASSERT(NULL != serverInfo);
171
if (Atomic_FetchAndDec(&serverInfo->refCount) == 1) {
172
HgfsChannelTeardownServer(serverInfo);
178
*----------------------------------------------------------------------------
180
* HgfsChannelInitServer --
182
* Initialize HGFS server and save the state.
185
* TRUE if success, FALSE otherwise.
190
*----------------------------------------------------------------------------
194
HgfsChannelInitServer(HgfsChannelServerData *serverInfo) // IN/OUT: ref count
198
ASSERT(NULL == serverInfo->serverCBTable);
200
Debug("%s: Initialize Hgfs server.\n", __FUNCTION__);
201
/* If we have a new connection initialize the server session. */
202
result = HgfsServer_InitState(&serverInfo->serverCBTable, NULL);
204
Debug("%s: Could not init Hgfs server.\n", __FUNCTION__);
211
*----------------------------------------------------------------------------
213
* HgfsChannelExitServer --
215
* Reset the HGFS server and destroy the state.
223
*----------------------------------------------------------------------------
227
HgfsChannelExitServer(HgfsChannelServerData *serverInfo) // IN/OUT: ref count
229
if (NULL != serverInfo->serverCBTable) {
230
Debug("%s: Teardown Hgfs server.\n", __FUNCTION__);
231
HgfsServer_ExitState();
232
serverInfo->serverCBTable = NULL;
238
*----------------------------------------------------------------------------
240
* HgfsChannelTeardownServer --
242
* Teardown the HGFS server state for all connections.
250
*----------------------------------------------------------------------------
254
HgfsChannelTeardownServer(HgfsChannelServerData *serverInfo) // IN/OUT: connection manager object
256
HgfsChannelExitServer(serverInfo);
261
*----------------------------------------------------------------------------
263
* CHANNEL DATA FUNCTIONS
265
*----------------------------------------------------------------------------
270
*----------------------------------------------------------------------------
272
* HgfsChannelGetChannel --
274
* Increment channel data reference count.
277
* The value of the reference count before the increment.
282
*----------------------------------------------------------------------------
286
HgfsChannelGetChannel(HgfsChannelData *channel) // IN/OUT: ref count
288
ASSERT(NULL != channel);
289
return Atomic_FetchAndInc(&channel->refCount);
294
*----------------------------------------------------------------------------
296
* HgfsChannelPutChannel --
298
* Decrement channel reference count.
300
* Teardown channel object if removed the final reference.
308
*----------------------------------------------------------------------------
312
HgfsChannelPutChannel(HgfsChannelData *channel) // IN/OUT: ref count
314
ASSERT(NULL != channel);
315
if (Atomic_FetchAndDec(&channel->refCount) == 1) {
316
HgfsChannelTeardownChannel(channel);
322
*-----------------------------------------------------------------------------
324
* HgfsChannelInitChannel --
326
* Initializes a channel by initializing the HGFS server state.
329
* TRUE if the channel initialized, FALSE otherwise.
334
*-----------------------------------------------------------------------------
338
HgfsChannelInitChannel(HgfsChannelData *channel, // IN/OUT: channel object
339
HgfsChannelServerData *serverInfo) // IN/OUT: server info
342
uint32 serverInfoCount;
346
* Reference the HGFS server as it will be used by the new channel.
347
* The HGFS server should only be initialized once, i.e. on the first
348
* caller instance, otherwise only reference the server info for
351
serverInfoCount = HgfsChannelGetServer(serverInfo);
352
/* Referenced the server, save it for dereferencing. */
353
channel->serverInfo = serverInfo;
354
if (0 == serverInfoCount) {
355
/* The HGFS server has not been initialized, do it now. */
356
result = HgfsChannelInitServer(channel->serverInfo);
358
Debug("%s: Could not init Hgfs server.\n", __FUNCTION__);
363
channel->state |= HGFS_CHANNEL_STATE_INIT;
367
HgfsChannelExitChannel(channel);
369
Debug("%s: Init channel return %d.\n", __FUNCTION__, result);
375
*-----------------------------------------------------------------------------
377
* HgfsChannelExitChannel --
379
* Teardown the channel and teardown the HGFS server.
387
*-----------------------------------------------------------------------------
391
HgfsChannelExitChannel(HgfsChannelData *channel) // IN/OUT: channel object
393
if (NULL != channel->serverInfo) {
394
/* Remove the reference for the HGFS server info. */
395
HgfsChannelPutServer(channel->serverInfo);
396
channel->serverInfo = NULL;
399
Debug("%s: Exit channel returns.\n", __FUNCTION__);
404
*-----------------------------------------------------------------------------
406
* HgfsChannelActivateChannel --
408
* Activate a channel by calling the channels init callback.
411
* TRUE if a channel is active.
416
*-----------------------------------------------------------------------------
420
HgfsChannelActivateChannel(HgfsChannelData *channel, // IN/OUT: channel object
421
void *rpc, // IN: Rpc channel
422
void *rpcCallback) // IN: Rpc callback
424
Bool success = FALSE;
425
struct HgfsGuestConn *connData = NULL;
427
if (channel->ops->init(channel->serverInfo->serverCBTable,
431
channel->state |= HGFS_CHANNEL_STATE_CBINIT;
432
channel->connection = connData;
440
*-----------------------------------------------------------------------------
442
* HgfsChannelDeactivateChannel --
444
* Deactivate a channel by calling the channels exit callback.
452
*-----------------------------------------------------------------------------
456
HgfsChannelDeactivateChannel(HgfsChannelData *channel) // IN/OUT: channel object
458
channel->ops->exit(channel->connection);
459
channel->state &= ~HGFS_CHANNEL_STATE_CBINIT;
460
channel->connection = NULL;
465
*-----------------------------------------------------------------------------
467
* HgfsChannelIsChannelActive --
469
* Is the channel active (initialized) for processing requests.
472
* TRUE if a channel is active.
477
*-----------------------------------------------------------------------------
481
HgfsChannelIsChannelActive(HgfsChannelData *channel) // IN/OUT: channel object
483
return (0 != (channel->state & HGFS_CHANNEL_STATE_INIT) &&
484
0 != (channel->state & HGFS_CHANNEL_STATE_CBINIT));
489
*-----------------------------------------------------------------------------
491
* HgfsChannelReceive --
493
* Received a request on a channel pass on to the channel callback.
496
* TRUE if a channel ws deactivated.
501
*-----------------------------------------------------------------------------
505
HgfsChannelReceive(HgfsChannelData *channel, // IN/OUT: channel object
506
char const *packetIn, // IN: incoming packet
507
size_t packetInSize, // IN: incoming packet size
508
char *packetOut, // OUT: outgoing packet
509
size_t *packetOutSize) // IN/OUT: outgoing packet size
511
return channel->ops->receive(channel->connection,
520
*----------------------------------------------------------------------------
522
* HgfsChannelTeardownChannel --
524
* Teardown the channel for HGFS.
532
*----------------------------------------------------------------------------
536
HgfsChannelTeardownChannel(HgfsChannelData *channel) // IN/OUT: connection manager object
538
if (HgfsChannelIsChannelActive(channel)) {
539
HgfsChannelDeactivateChannel(channel);
541
HgfsChannelExitChannel(channel);
546
*----------------------------------------------------------------------------
548
* CHANNEL PUBLIC FUNCTIONS
550
*----------------------------------------------------------------------------
555
*----------------------------------------------------------------------------
557
* HgfsChannelGuest_Init --
559
* Sets up the channel for HGFS.
561
* Initialize all the defined channels.
562
* At least one channel should succeed it's initialization
563
* completely, else we fail.
566
* TRUE on success, FALSE on failure.
571
*----------------------------------------------------------------------------
575
HgfsChannelGuest_Init(HgfsServerMgrData *mgrData) // IN/OUT: connection manager object
577
Bool success = FALSE;
578
HgfsChannelData *channel = &gHgfsChannels[0]; // Shared channel (internal RPC)
579
uint32 channelRefCount;
581
ASSERT(NULL != mgrData);
582
ASSERT(NULL == mgrData->connection);
583
/* Currently, the RPC override is not implemented. */
584
ASSERT(NULL == mgrData->rpc);
585
ASSERT(NULL == mgrData->rpcCallback);
586
ASSERT(NULL != mgrData->appName);
588
Debug("%s: app %s rpc = %p rpc cb = %p.\n", __FUNCTION__,
589
mgrData->appName, mgrData->rpc, mgrData->rpcCallback);
591
if (NULL != mgrData->rpc || NULL != mgrData->rpcCallback) {
593
* XXX - Would malloc a new channel here and activate
594
* with the required RPC.
597
Debug("%s: Guest channel RPC override not supported.\n", __FUNCTION__);
602
* Reference the channel. Initialize only for the first
603
* caller instance, otherwise only reference the channel for
604
* return to the caller.
606
channelRefCount = HgfsChannelGetChannel(channel);
607
/* We have referenced the channel, save it for later dereference. */
608
mgrData->connection = channel;
609
if (0 == channelRefCount) {
611
/* Initialize channels objects. */
612
if (!HgfsChannelInitChannel(channel, &gHgfsChannelServerInfo)) {
613
Debug("%s: Could not init channel.\n", __FUNCTION__);
617
/* Call the channels initializers. */
618
if (!HgfsChannelActivateChannel(channel,
620
mgrData->rpcCallback)) {
621
Debug("%s: Could not activate channel.\n", __FUNCTION__);
630
HgfsChannelGuest_Exit(mgrData);
637
*----------------------------------------------------------------------------
639
* HgfsChannelGuest_Exit --
641
* Dereference the channel which for the final reference will
642
* close the channel for HGFS.
650
*----------------------------------------------------------------------------
654
HgfsChannelGuest_Exit(HgfsServerMgrData *mgrData) // IN/OUT: connection manager object
656
HgfsChannelData *channel;
658
ASSERT(NULL != mgrData);
659
ASSERT(NULL != mgrData->appName);
661
channel = mgrData->connection;
663
Debug("%s: app %s rpc = %p rpc cb = %p chn = %p.\n", __FUNCTION__,
664
mgrData->appName, mgrData->rpc, mgrData->rpcCallback, channel);
666
if (NULL != channel) {
667
HgfsChannelPutChannel(channel);
668
mgrData->connection = NULL;
674
*----------------------------------------------------------------------------
676
* HgfsChannelGuest_Receive --
678
* Process packet not associated with an HGFS only registered callback.
682
* TRUE if successfully processed FALSE otherwise.
687
*----------------------------------------------------------------------------
691
HgfsChannelGuest_Receive(HgfsServerMgrData *mgrData, // IN/OUT : conn manager
692
char const *packetIn, // IN: incoming packet
693
size_t packetInSize, // IN: incoming packet size
694
char *packetOut, // OUT: outgoing packet
695
size_t *packetOutSize) // IN/OUT: outgoing packet size
697
HgfsChannelData *channel = NULL;
700
ASSERT(NULL != mgrData);
701
ASSERT(NULL != mgrData->connection);
702
ASSERT(NULL != mgrData->appName);
704
channel = mgrData->connection;
706
Debug("%s: %s Channel receive request.\n", __FUNCTION__, mgrData->appName);
708
if (HgfsChannelIsChannelActive(channel)) {
709
result = HgfsChannelReceive(channel,
716
Debug("%s: Channel receive returns %#x.\n", __FUNCTION__, result);