/** Reply from host when the command is not recognized. */
#define RPCI_UNKNOWN_COMMAND "Unknown command"
-#define GUESTRPC_VSOCK_LISTEN_PORT 975
+#define GUESTRPC_TCLO_VSOCK_LISTEN_PORT 975
+#define GUESTRPC_RPCI_VSOCK_LISTEN_PORT 976
/*
* Tools options.
#define RPCIN_TCLO_PING 0x1
enum {
- RPCINPKT_TYPE_DATA = 1,
- RPCINPKT_TYPE_PING
+ GUESTRPCPKT_TYPE_DATA = 1,
+ GUESTRPCPKT_TYPE_PING
};
enum {
- RPCINPKT_FIELD_TYPE = 1,
- RPCINPKT_FIELD_PAYLOAD
+ GUESTRPCPKT_FIELD_TYPE = 1,
+ GUESTRPCPKT_FIELD_PAYLOAD
};
#endif /* _TCLODEFS_H_ */
#define RPCIN_SETRETVALS RpcChannel_SetRetVals
#define RPCIN_SETRETVALSF RpcChannel_SetRetValsF
-struct RpcChannel;
+typedef struct _RpcChannel RpcChannel;
/** Data structure passed to RPC callbacks. */
typedef struct RpcInData {
void *clientData;
} RpcInData;
+typedef enum RpcChannelType {
+ RPCCHANNEL_TYPE_INACTIVE,
+ RPCCHANNEL_TYPE_BKDOOR,
+ RPCCHANNEL_TYPE_PRIV_VSOCK,
+ RPCCHANNEL_TYPE_UNPRIV_VSOCK
+} RpcChannelType;
/**
* Type for RpcIn callbacks. The callback function is responsible for
size_t xdrInSize;
} RpcChannelCallback;
-
-typedef gboolean (*RpcChannelStartFn)(struct RpcChannel *);
-typedef void (*RpcChannelStopFn)(struct RpcChannel *);
-typedef void (*RpcChannelShutdownFn)(struct RpcChannel *);
-typedef gboolean (*RpcChannelSendFn)(struct RpcChannel *,
- char const *data,
- size_t dataLen,
- char **result,
- size_t *resultLen);
-typedef void (*RpcChannelSetupFn)(struct RpcChannel *chan,
- GMainContext *mainCtx,
- const char *appName,
- gpointer appCtx);
-
-
/**
* Signature for the callback function called after a channel reset.
*
* @param[in] success Whether reset was successful.
* @param[in] data Client data.
*/
-typedef void (*RpcChannelResetCb)(struct RpcChannel *chan,
+typedef void (*RpcChannelResetCb)(RpcChannel *chan,
gboolean success,
gpointer data);
+gboolean
+RpcChannel_Start(RpcChannel *chan);
-/** Defines the interface between the application and the RPC channel. */
-typedef struct RpcChannel {
- RpcChannelStartFn start;
- RpcChannelStopFn stop;
- RpcChannelSendFn send;
- RpcChannelSetupFn setup;
- RpcChannelShutdownFn shutdown;
- gpointer _private;
-} RpcChannel;
-
-
-/**
- * Wrapper for the start function of an RPC channel struct.
- *
- * @param[in] chan The RPC channel instance.
- *
- * @return TRUE on success.
- */
-
-G_INLINE_FUNC gboolean
-RpcChannel_Start(RpcChannel *chan)
-{
- g_return_val_if_fail(chan != NULL, FALSE);
- g_return_val_if_fail(chan->start != NULL, FALSE);
-
- return chan->start(chan);
-}
-
-
-/**
- * Wrapper for the stop function of an RPC channel struct.
- *
- * @param[in] chan The RPC channel instance.
- */
-
-G_INLINE_FUNC void
-RpcChannel_Stop(RpcChannel *chan)
-{
- g_return_if_fail(chan != NULL);
- g_return_if_fail(chan->stop != NULL);
-
- chan->stop(chan);
-}
-
+void
+RpcChannel_Stop(RpcChannel *chan);
-/**
- * Wrapper for the send function of an RPC channel struct.
- *
- * @param[in] chan The RPC channel instance.
- * @param[in] data Data to send.
- * @param[in] dataLen Number of bytes to send.
- * @param[out] result Response from other side (should be freed by caller).
- * @param[out] resultLen Number of bytes in response.
- *
- * @return The status from the remote end (TRUE if call was successful).
- */
+RpcChannelType
+RpcChannel_GetType(RpcChannel *chan);
-G_INLINE_FUNC gboolean
+gboolean
RpcChannel_Send(RpcChannel *chan,
char const *data,
size_t dataLen,
char **result,
- size_t *resultLen)
-{
- g_return_val_if_fail(chan != NULL, FALSE);
- g_return_val_if_fail(chan->send != NULL, FALSE);
-
- return chan->send(chan, data, dataLen, result, resultLen);
-}
+ size_t *resultLen);
gboolean
RpcChannel_BuildXdrCommand(const char *cmd,
RpcChannel *
RpcChannel_Create(void);
+void
+RpcChannel_Shutdown(RpcChannel *chan);
+
gboolean
RpcChannel_Destroy(RpcChannel *chan);
RpcChannel_UnregisterCallback(RpcChannel *chan,
RpcChannelCallback *rpc);
+gboolean
+RpcChannel_SendOneRaw(const char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen);
+
+RpcChannel *
+RpcChannel_New(void);
+/* This is deprecated, call RpcChannel_New instead */
RpcChannel *
BackdoorChannel_New(void);
libRpcChannel_la_SOURCES =
libRpcChannel_la_SOURCES += bdoorChannel.c
libRpcChannel_la_SOURCES += rpcChannel.c
+libRpcChannel_la_SOURCES += vsockChannel.c
+libRpcChannel_la_SOURCES += simpleSocket.c
libRpcChannel_la_CPPFLAGS =
libRpcChannel_la_CPPFLAGS += @VMTOOLS_CPPFLAGS@
#include "rpcout.h"
#include "util.h"
-/** Max amount of time (in .01s) that the RpcIn loop will sleep for. */
-#define RPCIN_MAX_DELAY 10
-
typedef struct BackdoorChannel {
- GMainContext *mainCtx;
- GStaticMutex outLock;
- RpcIn *in;
- RpcOut *out;
- gboolean inStarted;
- gboolean outStarted;
+ RpcOut *out;
} BackdoorChannel;
-/**
- * Initializes internal state for the inbound channel.
- *
- * @param[in] chan The RPC channel instance.
- * @param[in] ctx Main application context.
- * @param[in] appName Unused.
- * @param[in] appCtx Unused.
- */
-
-static void
-RpcInSetup(RpcChannel *chan,
- GMainContext *ctx,
- const char *appName,
- gpointer appCtx)
-{
- BackdoorChannel *bdoor = chan->_private;
- bdoor->mainCtx = g_main_context_ref(ctx);
- bdoor->in = RpcIn_Construct(ctx, RpcChannel_Dispatch, chan);
- ASSERT(bdoor->in != NULL);
-}
-
-
/**
* Starts the RpcIn loop and the RpcOut channel.
*
*/
static gboolean
-RpcInStart(RpcChannel *chan)
+BkdoorChannelStart(RpcChannel *chan)
{
gboolean ret = TRUE;
BackdoorChannel *bdoor = chan->_private;
- if (bdoor->outStarted) {
- /* Already started. Make sure both channels are in sync and return. */
- ASSERT(bdoor->in == NULL || bdoor->inStarted);
- return ret;
- } else {
- ASSERT(bdoor->in == NULL || !bdoor->inStarted);
- }
-
- if (bdoor->in != NULL) {
- ret = RpcIn_start(bdoor->in, RPCIN_MAX_DELAY, RpcChannel_Error, chan);
- }
+ ret = chan->in == NULL || chan->inStarted;
if (ret) {
ret = RpcOut_start(bdoor->out);
if (!ret) {
- RpcIn_stop(bdoor->in);
+ if (chan->inStarted) {
+ RpcIn_stop(chan->in);
+ chan->inStarted = FALSE;
+ }
}
}
- bdoor->inStarted = (bdoor->in != NULL);
- bdoor->outStarted = TRUE;
+ chan->outStarted = ret;
return ret;
}
*/
static void
-RpcInStop(RpcChannel *chan)
+BkdoorChannelStop(RpcChannel *chan)
{
BackdoorChannel *bdoor = chan->_private;
- g_static_mutex_lock(&bdoor->outLock);
if (bdoor->out != NULL) {
- if (bdoor->outStarted) {
+ if (chan->outStarted) {
RpcOut_stop(bdoor->out);
}
- bdoor->outStarted = FALSE;
+ chan->outStarted = FALSE;
} else {
- ASSERT(!bdoor->outStarted);
- }
- g_static_mutex_unlock(&bdoor->outLock);
-
- if (bdoor->in != NULL) {
- if (bdoor->inStarted) {
- RpcIn_stop(bdoor->in);
- }
- bdoor->inStarted = FALSE;
- } else {
- ASSERT(!bdoor->inStarted);
+ ASSERT(!chan->outStarted);
}
}
*/
static void
-RpcInShutdown(RpcChannel *chan)
+BkdoorChannelShutdown(RpcChannel *chan)
{
BackdoorChannel *bdoor = chan->_private;
- RpcInStop(chan);
- if (bdoor->in != NULL) {
- RpcIn_Destruct(bdoor->in);
- }
+ BkdoorChannelStop(chan);
RpcOut_Destruct(bdoor->out);
- g_static_mutex_free(&bdoor->outLock);
- if (bdoor->mainCtx != NULL) {
- g_main_context_unref(bdoor->mainCtx);
- }
g_free(bdoor);
+ chan->_private = NULL;
}
*/
static gboolean
-RpcInSend(RpcChannel *chan,
- char const *data,
- size_t dataLen,
- char **result,
- size_t *resultLen)
+BkdoorChannelSend(RpcChannel *chan,
+ char const *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen)
{
gboolean ret = FALSE;
const char *reply;
size_t replyLen;
BackdoorChannel *bdoor = chan->_private;
- g_static_mutex_lock(&bdoor->outLock);
- if (!bdoor->outStarted) {
+ if (!chan->outStarted) {
goto exit;
}
} else {
g_warning("Couldn't restart RpcOut channel; bad things may happen "
"until the RPC channel is reset.\n");
- bdoor->outStarted = FALSE;
+ chan->outStarted = FALSE;
}
}
}
exit:
- g_static_mutex_unlock(&bdoor->outLock);
return ret;
}
+/**
+ * Return the channel type.
+ *
+ * @param[in] chan RpcChannel
+ *
+ * @return backdoor channel type.
+ */
+
+static RpcChannelType
+BkdoorChannelGetType(RpcChannel *chan)
+{
+ return RPCCHANNEL_TYPE_BKDOOR;
+}
+
+
+/**
+ * Helper function to setup RpcChannel callbacks.
+ *
+ * @param[in] chan RpcChannel
+ */
+
+static void
+BackdoorChannelSetCallbacks(RpcChannel *chan)
+{
+ static RpcChannelFuncs funcs = {
+ BkdoorChannelStart,
+ BkdoorChannelStop,
+ BkdoorChannelSend,
+ NULL,
+ BkdoorChannelShutdown,
+ BkdoorChannelGetType,
+ NULL,
+ NULL
+ };
+
+ ASSERT(chan);
+ chan->funcs = &funcs;
+}
+
+
/**
* Creates a new RpcChannel channel that uses the backdoor for communication.
*
ret = RpcChannel_Create();
bdoor = g_malloc0(sizeof *bdoor);
- g_static_mutex_init(&bdoor->outLock);
bdoor->out = RpcOut_Construct();
ASSERT(bdoor->out != NULL);
- bdoor->inStarted = FALSE;
- bdoor->outStarted = FALSE;
+ ret->inStarted = FALSE;
+ ret->outStarted = FALSE;
- ret->start = RpcInStart;
- ret->stop = RpcInStop;
- ret->send = RpcInSend;
- ret->setup = RpcInSetup;
- ret->shutdown = RpcInShutdown;
+ BackdoorChannelSetCallbacks(ret);
ret->_private = bdoor;
return ret;
}
+
+/**
+ * Fall back to backdoor when another type of RpcChannel fails to start.
+ *
+ * @param[in] chan RpcChannel
+ *
+ * @return TRUE on success.
+ */
+
+gboolean
+BackdoorChannel_Fallback(RpcChannel *chan)
+{
+ BackdoorChannel *bdoor;
+
+ ASSERT(chan);
+ ASSERT(chan->_private == NULL);
+
+ bdoor = g_malloc0(sizeof *bdoor);
+ bdoor->out = RpcOut_Construct();
+ ASSERT(bdoor->out != NULL);
+
+ BackdoorChannelSetCallbacks(chan);
+ chan->_private = bdoor;
+
+ return chan->funcs->start(chan);
+}
+
#include "strutil.h"
#include "vmxrpc.h"
#include "xdrutil.h"
+#include "rpcin.h"
/** Internal state of a channel. */
typedef struct RpcChannelInt {
guint rpcErrorCount;
} RpcChannelInt;
-
/** Max number of times to attempt a channel restart. */
#define RPCIN_MAX_RESTARTS 60
+#define LGPFX "RpcChannel: "
+
static gboolean
RpcChannelPing(RpcInData *data);
size_t i;
RpcChannelInt *cdata = (RpcChannelInt *) chan;
- if (cdata->impl.shutdown != NULL) {
- cdata->impl.shutdown(chan);
+ if (cdata->impl.funcs != NULL && cdata->impl.funcs->shutdown != NULL) {
+ cdata->impl.funcs->shutdown(chan);
}
RpcChannel_UnregisterCallback(chan, &cdata->resetReg);
RpcChannel_RegisterCallback(chan, &gRpcHandlers[i]);
}
- if (cdata->impl.setup != NULL) {
- cdata->impl.setup(&cdata->impl, mainCtx, appName, appCtx);
+ if (chan->funcs != NULL && chan->funcs->setup != NULL) {
+ chan->funcs->setup(chan, mainCtx, appName, appCtx);
+ } else {
+ chan->mainCtx = g_main_context_ref(mainCtx);
+ chan->in = RpcIn_Construct(mainCtx, RpcChannel_Dispatch, chan);
+ ASSERT(chan->in != NULL);
}
}
}
}
+
+/**
+ * Create an RpcChannel instance using a prefered channel implementation,
+ * currently this is VSockChannel.
+ *
+ * @return RpcChannel
+ */
+
+RpcChannel *
+RpcChannel_New(void)
+{
+ RpcChannel *chan;
+#if defined(linux) || defined(_WIN32)
+ chan = VSockChannel_New();
+#else
+ chan = BackdoorChannel_New();
+#endif
+ if (chan) {
+ g_static_mutex_init(&chan->outLock);
+ }
+ return chan;
+}
+
+
+/**
+ * Wrapper for the shutdown function of an RPC channel struct.
+ *
+ * @param[in] chan The RPC channel instance.
+ */
+
+void
+RpcChannel_Shutdown(RpcChannel *chan)
+{
+ if (chan != NULL) {
+ g_static_mutex_free(&chan->outLock);
+ }
+
+ if (chan != NULL && chan->funcs != NULL && chan->funcs->shutdown != NULL) {
+ if (chan->in != NULL) {
+ RpcIn_Destruct(chan->in);
+ }
+ if (chan->mainCtx != NULL) {
+ g_main_context_unref(chan->mainCtx);
+ }
+ chan->funcs->shutdown(chan);
+ }
+}
+
+
+/**
+ * Start an RPC channel. We may fallback to backdoor channel when other type
+ * of channel fails to start.
+ *
+ * @param[in] chan The RPC channel instance.
+ *
+ * @return TRUE on success.
+ */
+
+gboolean
+RpcChannel_Start(RpcChannel *chan)
+{
+ gboolean ok;
+ const RpcChannelFuncs *funcs;
+
+ if (chan == NULL || chan->funcs == NULL || chan->funcs->start == NULL) {
+ return FALSE;
+ }
+
+ if (chan->outStarted) {
+ /* Already started. Make sure both channels are in sync and return. */
+ ASSERT(chan->in == NULL || chan->inStarted);
+ return TRUE;
+ } else {
+ ASSERT(chan->in == NULL || !chan->inStarted);
+ }
+
+ if (chan->in != NULL) {
+ ok = RpcIn_start(chan->in, RPCIN_MAX_DELAY, RpcChannel_Error, chan);
+ chan->inStarted = ok;
+ }
+
+ funcs = chan->funcs;
+ ok = funcs->start(chan);
+
+ if (!ok && funcs->onStartErr != NULL) {
+ g_warning(LGPFX "Fallback to backdoor ...\n");
+ funcs->onStartErr(chan);
+ ok = BackdoorChannel_Fallback(chan);
+ }
+
+ return ok;
+}
+
+
+/**
+ * Wrapper for the stop function of an RPC channel struct.
+ *
+ * @param[in] chan The RPC channel instance.
+ */
+
+void
+RpcChannel_Stop(RpcChannel *chan)
+{
+ g_return_if_fail(chan != NULL);
+ g_return_if_fail(chan->funcs != NULL);
+ g_return_if_fail(chan->funcs->stop != NULL);
+
+ g_static_mutex_lock(&chan->outLock);
+ chan->funcs->stop(chan);
+
+ if (chan->in != NULL) {
+ if (chan->inStarted) {
+ RpcIn_stop(chan->in);
+ }
+ chan->inStarted = FALSE;
+ } else {
+ ASSERT(!chan->inStarted);
+ }
+ g_static_mutex_unlock(&chan->outLock);
+}
+
+
+/**
+ * Wrapper for get channel type function of an RPC channel struct.
+ *
+ * @param[in] chan The RPC channel instance.
+ */
+
+RpcChannelType
+RpcChannel_GetType(RpcChannel *chan)
+{
+ if (chan == NULL || chan->funcs == NULL || chan->funcs->getType == NULL) {
+ return RPCCHANNEL_TYPE_INACTIVE;
+ }
+ return chan->funcs->getType(chan);
+}
+
+
+/**
+ * Send function of an RPC channel struct. Retry once if it fails for
+ * non-backdoor Channels. Backdoor channel already tries inside. A second try
+ * may create a different type of channel.
+ *
+ * @param[in] chan The RPC channel instance.
+ * @param[in] data Data to send.
+ * @param[in] dataLen Number of bytes to send.
+ * @param[out] result Response from other side (should be freed by caller).
+ * @param[out] resultLen Number of bytes in response.
+ *
+ * @return The status from the remote end (TRUE if call was successful).
+ */
+
+gboolean
+RpcChannel_Send(RpcChannel *chan,
+ char const *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen)
+{
+ gboolean ok;
+ char *res = NULL;
+ size_t resLen = 0;
+ const RpcChannelFuncs *funcs;
+
+ g_debug(LGPFX "Sending: %"FMTSZ"u bytes\n", dataLen);
+
+ ASSERT(chan && chan->funcs);
+
+ g_static_mutex_lock(&chan->outLock);
+
+ funcs = chan->funcs;
+ ASSERT(funcs->send);
+
+ if (result != NULL) {
+ *result = NULL;
+ }
+ if (resultLen != NULL) {
+ *resultLen = 0;
+ }
+
+ ok = funcs->send(chan, data, dataLen, &res, &resLen);
+
+ if (!ok && (funcs->getType(chan) != RPCCHANNEL_TYPE_BKDOOR) &&
+ (funcs->stopRpcOut != NULL)) {
+
+ free(res);
+ res = NULL;
+ resLen = 0;
+
+ /* retry once */
+ g_debug(LGPFX "Stop RpcOut channel and try to send again ...\n");
+ funcs->stopRpcOut(chan);
+ if (RpcChannel_Start(chan)) {
+ ok = funcs->send(chan, data, dataLen, &res, &resLen);
+ goto done;
+ }
+
+ ok = FALSE;
+ goto exit;
+ }
+
+done:
+ if (ok) {
+ g_debug(LGPFX "Recved %"FMTSZ"u bytes\n", resLen);
+ }
+
+ if (result != NULL) {
+ *result = res;
+ }
+ if (resultLen != NULL) {
+ *resultLen = resLen;
+ }
+
+exit:
+ g_static_mutex_unlock(&chan->outLock);
+ return ok;
+}
+
+
+/**
+ * Open/close RpcChannel each time for sending a Rpc message, this is a wrapper
+ * for RpcChannel APIs.
+ *
+ * @param[in] data request data
+ * @param[in] dataLen data length
+ * @param[in] result reply
+ * @param[in] resultLen reply length
+
+ * @returns TRUE on success.
+ */
+
+gboolean
+RpcChannel_SendOneRaw(const char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen)
+{
+ RpcChannel *chan;
+ gboolean status;
+
+ status = FALSE;
+
+ chan = RpcChannel_New();
+ if (chan == NULL) {
+ if (result != NULL) {
+ *result = Util_SafeStrdup("RpcChannel: Unable to create "
+ "the RpcChannel object");
+ if (resultLen != NULL) {
+ *resultLen = strlen(*result);
+ }
+ }
+ goto sent;
+ } else if (!RpcChannel_Start(chan)) {
+ if (result != NULL) {
+ *result = Util_SafeStrdup("RpcChannel: Unable to open the "
+ "communication channel");
+ if (resultLen != NULL) {
+ *resultLen = strlen(*result);
+ }
+ }
+ goto sent;
+ } else if (!RpcChannel_Send(chan, data, dataLen, result, resultLen)) {
+ /* We already have the description of the error */
+ goto sent;
+ }
+
+ status = TRUE;
+
+sent:
+ g_debug(LGPFX "Request %s: reqlen=%"FMTSZ"u, replyLen=%"FMTSZ"u\n",
+ status ? "OK" : "FAILED", dataLen, *resultLen);
+ if (chan) {
+ RpcChannel_Stop(chan);
+ RpcChannel_Destroy(chan);
+ }
+
+ return status;
+}
#include "vmware/tools/guestrpc.h"
+/** Max amount of time (in .01s) that the RpcIn loop will sleep for. */
+#define RPCIN_MAX_DELAY 10
+
+struct RpcIn;
+
+/** a list of interface functions for a channel implementation */
+typedef struct _RpcChannelFuncs{
+ gboolean (*start)(RpcChannel *);
+ void (*stop)(RpcChannel *);
+ gboolean (*send)(RpcChannel *, char const *data, size_t dataLen,
+ char **result, size_t *resultLen);
+ void (*setup)(RpcChannel *chan, GMainContext *mainCtx,
+ const char *appName, gpointer appCtx);
+ void (*shutdown)(RpcChannel *);
+ RpcChannelType (*getType)(RpcChannel *chan);
+ void (*onStartErr)(RpcChannel *);
+ gboolean (*stopRpcOut)(RpcChannel *);
+} RpcChannelFuncs;
+
+/** Defines the interface between the application and the RPC channel. */
+struct _RpcChannel {
+ const RpcChannelFuncs *funcs;
+ gpointer _private;
+ GMainContext *mainCtx;
+ const char *appName;
+ gpointer appCtx;
+ GStaticMutex outLock;
+ struct RpcIn *in;
+ gboolean inStarted;
+ gboolean outStarted;
+};
+
void
RpcChannel_Error(void *_state,
char const *status);
+RpcChannel *VSockChannel_New(void);
+RpcChannel *BackdoorChannel_New(void);
+gboolean
+BackdoorChannel_Fallback(RpcChannel *chan);
#endif /* _RPCCHANNELINT_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2013 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * simpleSocket.c --
+ *
+ * Simple wrappers for socket.
+ *
+ */
+
+#include <stdlib.h>
+#if defined(linux)
+#include <arpa/inet.h>
+#endif
+
+#include "simpleSocket.h"
+#include "vmci_defs.h"
+#include "vmci_sockets.h"
+#include "dataMap.h"
+#include "err.h"
+
+#define LGPFX "SimpleSock: "
+
+
+static int
+SocketGetLastError(void);
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SocketStartup --
+ *
+ * Win32 special socket init.
+ *
+ * Results:
+ * TRUE on success
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+SocketStartup(void)
+{
+#if defined(_WIN32)
+ int err;
+ WSADATA wsaData;
+
+ err = WSAStartup(MAKEWORD(2, 0), &wsaData);
+ if (err) {
+ g_warning(LGPFX "Error in WSAStartup: %d[%s]\n", err,
+ Err_Errno2String(err));
+ return FALSE;
+ }
+
+ if (2 != LOBYTE(wsaData.wVersion) || 0 != HIBYTE(wsaData.wVersion)) {
+ g_warning(LGPFX "Unsupported Winsock version %d.%d\n",
+ LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SocketCleanup --
+ *
+ * Win32 special socket cleanup.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+SocketCleanup(void)
+{
+#if defined(_WIN32)
+ int err = WSACleanup();
+ if (err) {
+ g_warning(LGPFX "Error in WSACleanup: %d[%s]\n", err,
+ Err_Errno2String(err));
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Socket_Close --
+ *
+ * wrapper for socket close.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Socket_Close(SOCKET sock)
+{
+ int res;
+
+#if defined(_WIN32)
+ res = closesocket(sock);
+#else
+ res = close(sock);
+#endif
+
+ if (res == SOCKET_ERROR) {
+ int err = SocketGetLastError();
+ g_warning(LGPFX "Error in closing socket %d: %d[%s]\n",
+ sock, err, Err_Errno2String(err));
+ }
+
+ SocketCleanup();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SocketGetLastError --
+ *
+ * Get the last error code.
+ *
+ * Results:
+ * error code.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+SocketGetLastError(void)
+{
+#if defined(_WIN32)
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Socket_Recv --
+ *
+ * Block until given number of bytes of data is received or error occurs.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+gboolean
+Socket_Recv(SOCKET fd, // IN
+ char *buf, // OUT
+ int len) // IN
+{
+ int remaining = len;
+ int rv;
+ int sysErr;
+
+ while (remaining > 0) {
+ rv = recv(fd, buf , remaining, 0);
+ if (rv == 0) {
+ g_warning(LGPFX "Socket %d closed by peer.", fd);
+ return FALSE;
+ }
+ if (rv == SOCKET_ERROR) {
+ sysErr = SocketGetLastError();
+ if (sysErr == SYSERR_EINTR) {
+ continue;
+ }
+ g_warning(LGPFX "Recv error for socket %d: %d[%s]", fd, sysErr,
+ Err_Errno2String(sysErr));
+ return FALSE;
+ }
+ remaining -= rv;
+ buf += rv;
+ }
+
+ g_debug(LGPFX "Recved %d bytes from socket %d\n", len, fd);
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Socket_Send --
+ *
+ * Block until the given number of bytes of data is sent or error occurs.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+gboolean
+Socket_Send(SOCKET fd, // IN
+ char *buf, // IN
+ int len) // IN
+{
+ int left = len;
+ int sent = 0;
+ int rv;
+ int sysErr;
+
+ while (left > 0) {
+ rv = send(fd, buf + sent, left, 0);
+ if (rv == SOCKET_ERROR) {
+ sysErr = SocketGetLastError();
+ if (sysErr == SYSERR_EINTR) {
+ continue;
+ }
+ g_warning(LGPFX "Send error for socket %d: %d[%s]", fd, sysErr,
+ Err_Errno2String(sysErr));
+ return FALSE;
+ }
+ left -= rv;
+ sent += rv;
+ }
+
+ g_debug(LGPFX "Sent %d bytes from socket %d\n", len, fd);
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Socket_ConnectVMCI --
+ *
+ * Connect to VMCI port in blocking mode.
+ * If isPriv is true, we will try to bind the local port to a port that
+ * is less than 1024.
+ *
+ * Results:
+ * returns the raw socket on sucess, otherwise INVALID_SOCKET;
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------------
+ */
+
+SOCKET
+Socket_ConnectVMCI(unsigned int cid, // IN
+ unsigned int port, // IN
+ gboolean isPriv, // IN
+ SockConnError *outError) // OUT
+{
+ struct sockaddr_vm addr;
+ SOCKET fd;
+ SockConnError error = SOCKERR_GENERIC;
+ int sysErr;
+ socklen_t addrLen = sizeof addr;
+
+ if (outError) {
+ *outError = SOCKERR_SUCCESS;
+ }
+
+ if (!SocketStartup()) {
+ goto error;
+ }
+
+ memset((char *)&addr, 0, sizeof addr);
+ addr.svm_family = VMCISock_GetAFValue();
+ addr.svm_cid = cid;
+ addr.svm_port = port;
+
+ g_debug(LGPFX "creating new socket, connecting to %u:%u\n", cid, port);
+
+ fd = socket(addr.svm_family, SOCK_STREAM, 0);
+ if (fd == INVALID_SOCKET) {
+ sysErr = SocketGetLastError();
+ g_warning(LGPFX "failed to create socket, error %d: %s\n",
+ sysErr, Err_Errno2String(sysErr));
+ goto error;
+ }
+
+ if (isPriv) {
+ struct sockaddr_vm localAddr;
+ gboolean bindOk = FALSE;
+ int localPort;
+
+ memset(&localAddr, 0, sizeof localAddr);
+ localAddr.svm_family = addr.svm_family;
+ localAddr.svm_cid = VMCISock_GetLocalCID();
+
+ /* Try to bind to port 1~1023 for a privileged user. */
+ for (localPort = PRIVILEGED_PORT_MAX;
+ localPort >= PRIVILEGED_PORT_MIN; localPort--) {
+
+ localAddr.svm_port = localPort;
+
+ if (bind(fd, (struct sockaddr *)&localAddr, sizeof localAddr) != 0) {
+ sysErr = SocketGetLastError();
+ if (sysErr == SYSERR_EACCESS) {
+ g_warning(LGPFX "Couldn't bind to privileged port for "
+ "socket %d\n", fd);
+ error = SOCKERR_EACCESS;
+ Socket_Close(fd);
+ goto error;
+ }
+ if (sysErr == SYSERR_EADDRINUSE) {
+ continue;
+ }
+ g_warning(LGPFX "could not bind socket, error %d: %s\n", sysErr,
+ Err_Errno2String(sysErr));
+ Socket_Close(fd);
+ error = SOCKERR_BIND;
+ goto error;
+ } else {
+ bindOk = TRUE;
+ break;
+ }
+ }
+
+ if (!bindOk) {
+ g_warning(LGPFX "Failed to bind to privileged port for socket %d, "
+ "no port available\n", fd);
+ error = SOCKERR_BIND;
+ Socket_Close(fd);
+ goto error;
+ } else {
+ g_debug(LGPFX "Successfully bound to port %d for socket %d\n",
+ localAddr.svm_port, fd);
+ }
+ }
+
+ if (connect(fd, (struct sockaddr *)&addr, addrLen) != 0) {
+ sysErr = SocketGetLastError();
+ g_warning(LGPFX "socket connect failed, error %d: %s\n",
+ sysErr, Err_Errno2String(sysErr));
+ Socket_Close(fd);
+ error = SOCKERR_CONNECT;
+ goto error;
+ }
+
+ g_debug(LGPFX "socket %d connected\n", fd);
+ return fd;
+
+error:
+ if (outError) {
+ *outError = error;
+ }
+
+ return INVALID_SOCKET;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Socket_DecodePacket --
+ *
+ * Helper function to decode received packet in DataMap encoding format.
+ *
+ * Result:
+ * None
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+Socket_DecodePacket(const char *recvBuf, // IN
+ int fullPktLen, // IN
+ char **payload, // OUT
+ int32 *payloadLen) // OUT
+{
+ ErrorCode res;
+ DataMap map;
+ char *buf;
+ int32 len;
+
+ *payload = NULL;
+ *payloadLen = 0;
+
+ /* decoding the packet */
+ res = DataMap_Deserialize(recvBuf, fullPktLen, &map);
+ if (res != DMERR_SUCCESS) {
+ g_debug(LGPFX "Error in dataMap decoding, error=%d\n", res);
+ return FALSE;
+ }
+
+ res = DataMap_GetString(&map, GUESTRPCPKT_FIELD_PAYLOAD, &buf, &len);
+ if (res == DMERR_SUCCESS) {
+ char *tmpPtr = malloc(len + 1);
+ if (tmpPtr == NULL) {
+ g_debug(LGPFX "Error in allocating memory\n");
+ goto error;
+ }
+ memcpy(tmpPtr, buf, len);
+ /* add a trailing 0 for backward compatibility */
+ tmpPtr[len] = '\0';
+
+ *payload = tmpPtr;
+ *payloadLen = len;
+ } else {
+ g_debug(LGPFX "Error in decoding payload, error=%d\n", res);
+ goto error;
+ }
+
+ DataMap_Destroy(&map);
+ return TRUE;
+
+error:
+ DataMap_Destroy(&map);
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Socket_PackSendData --
+ *
+ * Helper function for building send packet and serialize it.
+ *
+ * Result:
+ * TRUE on sucess, FALSE otherwise.
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+Socket_PackSendData(const char *buf, // IN
+ int len, // IN
+ char **serBuf, // OUT
+ int32 *serBufLen) // OUT
+{
+ DataMap map;
+ ErrorCode res;
+ char *newBuf;
+ gboolean mapCreated = FALSE;
+ int64 pktType = GUESTRPCPKT_TYPE_DATA;
+
+ res = DataMap_Create(&map);
+ if (res != DMERR_SUCCESS) {
+ goto error;
+ }
+
+ mapCreated = TRUE;
+ res = DataMap_SetInt64(&map, GUESTRPCPKT_FIELD_TYPE,
+ pktType, TRUE);
+ if (res != DMERR_SUCCESS) {
+ goto error;
+ }
+
+ newBuf = malloc(len);
+ if (newBuf == NULL) {
+ g_debug(LGPFX "Error in allocating memory.\n");
+ goto error;
+ }
+ memcpy(newBuf, buf, len);
+ res = DataMap_SetString(&map, GUESTRPCPKT_FIELD_PAYLOAD, newBuf,
+ len, TRUE);
+ if (res != DMERR_SUCCESS) {
+ free(newBuf);
+ goto error;
+ }
+
+ res = DataMap_Serialize(&map, serBuf, serBufLen);
+ if (res != DMERR_SUCCESS) {
+ goto error;
+ }
+
+ DataMap_Destroy(&map);
+ return TRUE;
+
+error:
+ if (mapCreated) {
+ DataMap_Destroy(&map);
+ }
+ g_debug(LGPFX "Error in dataMap encoding\n");
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Socket_RecvPacket --
+ *
+ * Helper function to recv a dataMap packet over the socket.
+ * The caller has to *free* the payload to avoid memory leak.
+ *
+ * Result:
+ * TRUE on sucess, FALSE otherwise.
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+gboolean
+Socket_RecvPacket(SOCKET sock, // IN
+ char **payload, // OUT
+ int *payloadLen) // OUT
+{
+ gboolean ok;
+ int32 packetLen;
+ int packetLenSize = sizeof packetLen;
+ int fullPktLen;
+ char *recvBuf;
+ int recvBufLen;
+
+ ok = Socket_Recv(sock, (char *)&packetLen, packetLenSize);
+ if (!ok) {
+ g_debug(LGPFX "error in recving packet header, err=%d\n",
+ SocketGetLastError());
+ return FALSE;
+ }
+
+ fullPktLen = ntohl(packetLen) + packetLenSize;
+ recvBufLen = fullPktLen;
+ recvBuf = malloc(recvBufLen);
+ if (recvBuf == NULL) {
+ g_debug(LGPFX "Could not allocate recv buffer.\n");
+ return FALSE;
+ }
+
+ memcpy(recvBuf, &packetLen, packetLenSize);
+ ok = Socket_Recv(sock, recvBuf + packetLenSize,
+ fullPktLen - packetLenSize);
+ if (!ok) {
+ g_debug(LGPFX "error in recving packet, err=%d\n",
+ SocketGetLastError());
+ free(recvBuf);
+ return FALSE;
+ }
+
+ ok = Socket_DecodePacket(recvBuf, fullPktLen, payload, payloadLen);
+ free(recvBuf);
+ return ok;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Socket_SendPacket --
+ *
+ * Helper function to send a dataMap packet over the socket.
+ *
+ * Result:
+ * TRUE on sucess, FALSE otherwise.
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+gboolean
+Socket_SendPacket(SOCKET sock, // IN
+ const char *payload, // IN
+ int payloadLen) // IN
+{
+ gboolean ok;
+ char *sendBuf;
+ int sendBufLen;
+
+ if (!Socket_PackSendData(payload, payloadLen, &sendBuf, &sendBufLen)) {
+ return FALSE;
+ }
+
+ ok = Socket_Send(sock, sendBuf, sendBufLen);
+ free(sendBuf);
+
+ return ok;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2013 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _SIMPLESOCKET_H_
+#define _SIMPLESOCKET_H_
+
+/**
+ * @file simpleSocket.h
+ *
+ * header of simple socket wrappers.
+ */
+
+#include <glib.h>
+
+#if defined(_WIN32)
+#include <winsock2.h>
+#include <winerror.h>
+#else
+#include <errno.h>
+#endif
+
+#include "vmci_defs.h"
+#include "vmware/guestrpc/tclodefs.h"
+
+typedef enum {
+ SOCKERR_SUCCESS,
+ SOCKERR_GENERIC,
+ SOCKERR_CONNECT,
+ SOCKERR_BIND,
+ SOCKERR_EACCESS
+} SockConnError;
+
+#if defined(_WIN32)
+
+#define SYSERR_EADDRINUSE WSAEADDRINUSE
+#define SYSERR_EACCESS WSAEACCES
+#define SYSERR_EINTR WSAEINTR
+
+typedef int socklen_t;
+
+#else /* !_WIN32 */
+
+#define SYSERR_EADDRINUSE EADDRINUSE
+#define SYSERR_EACCESS EACCES
+#define SYSERR_EINTR EINTR
+
+typedef int SOCKET;
+#define SOCKET_ERROR (-1)
+#define INVALID_SOCKET ((SOCKET) -1)
+
+#endif
+
+#define PRIVILEGED_PORT_MAX 1023
+#define PRIVILEGED_PORT_MIN 1
+
+void Socket_Close(SOCKET sock);
+SOCKET Socket_ConnectVMCI(unsigned int cid,
+ unsigned int port,
+ gboolean isPriv,
+ SockConnError *outError);
+gboolean Socket_Recv(SOCKET fd,
+ char *buf,
+ int len);
+gboolean Socket_Send(SOCKET fd,
+ char *buf,
+ int len);
+gboolean Socket_RecvPacket(SOCKET sock,
+ char **payload,
+ int *payloadLen);
+gboolean Socket_SendPacket(SOCKET sock,
+ const char *payload,
+ int payloadLen);
+
+#endif /* _SIMPLESOCKET_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2013 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * vsockChannel.c --
+ *
+ * Implement RpcChannel using vsocket.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "simpleSocket.h"
+#include "rpcChannelInt.h"
+#include "rpcin.h"
+#include "util.h"
+
+#define LGPFX "VSockChan: "
+
+typedef struct VSockOut {
+ SOCKET fd;
+ char *payload;
+ int payloadLen;
+ RpcChannelType type;
+} VSockOut;
+
+typedef struct VSockChannel {
+ VSockOut *out;
+} VSockChannel;
+
+static void VSockChannelShutdown(RpcChannel *chan);
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockCreateConn --
+ *
+ * Create vsocket connection. we try a privileged connection first,
+ * fallback to unprivileged one if that fails.
+ *
+ * Result:
+ * a valid socket/fd on success or INVALID_SOCKET on failure.
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static SOCKET
+VSockCreateConn(gboolean *isPriv) // OUT
+{
+ SockConnError err;
+ SOCKET fd;
+
+ g_debug(LGPFX "Creating privileged vsocket ...\n");
+ fd = Socket_ConnectVMCI(VMCI_HYPERVISOR_CONTEXT_ID,
+ GUESTRPC_RPCI_VSOCK_LISTEN_PORT,
+ TRUE, &err);
+
+ if (fd != INVALID_SOCKET) {
+ g_debug(LGPFX "Successfully created priv vsocket %d\n", fd);
+ *isPriv = TRUE;
+ return fd;
+ }
+
+ if (err == SOCKERR_EACCESS) {
+ g_debug(LGPFX "Creating unprivileged vsocket ...\n");
+ fd = Socket_ConnectVMCI(VMCI_HYPERVISOR_CONTEXT_ID,
+ GUESTRPC_RPCI_VSOCK_LISTEN_PORT,
+ FALSE, &err);
+ if (fd != INVALID_SOCKET) {
+ g_debug(LGPFX "Successfully created unpriv vsocket %d\n", fd);
+ *isPriv = FALSE;
+ return fd;
+ }
+ }
+
+ g_warning(LGPFX "Failed to create vsocket channel, err=%d\n", err);
+ return INVALID_SOCKET;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockOutConstruct --
+ *
+ * Constructor for the VSockOut object
+ *
+ * Results:
+ * New VSockOut object.
+ *
+ * Side effects:
+ * Allocates memory.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VSockOut *
+VSockOutConstruct(void)
+{
+ VSockOut *out = calloc(1, sizeof *out);
+
+ if (out != NULL) {
+ out->fd = INVALID_SOCKET;
+ out->type = RPCCHANNEL_TYPE_INACTIVE;
+ }
+ return out;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockOutDestruct --
+ *
+ * Destructor for the VSockOut object.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Frees VSockOut object memory.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VSockOutDestruct(VSockOut *out) // IN
+{
+
+ ASSERT(out);
+ ASSERT(out->fd == INVALID_SOCKET);
+
+ free(out->payload);
+ free(out);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockOutStart --
+ *
+ * Open the channel
+ *
+ * Result:
+ * TRUE on success
+ * FALSE on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+VSockOutStart(VSockOut *out) // IN
+{
+ gboolean isPriv;
+
+ ASSERT(out);
+ ASSERT(out->fd == INVALID_SOCKET);
+
+ out->fd = VSockCreateConn(&isPriv);
+ if (out->fd != INVALID_SOCKET) {
+ out->type = isPriv ? RPCCHANNEL_TYPE_PRIV_VSOCK :
+ RPCCHANNEL_TYPE_UNPRIV_VSOCK;
+ }
+ return out->fd != INVALID_SOCKET;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockOutStop --
+ *
+ * Close the channel
+ *
+ * Result
+ * TRUE on success
+ * FALSE on failure
+ *
+ * Side-effects
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+VSockOutStop(VSockOut *out) // IN
+{
+ ASSERT(out);
+
+ if (out->fd != INVALID_SOCKET) {
+ Socket_Close(out->fd);
+ out->fd = INVALID_SOCKET;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockOutSend --
+ *
+ * Make VMware synchronously execute a TCLO command
+ *
+ * Unlike the other send varieties, VSockOutSend requires that the
+ * caller pass non-NULL reply and repLen arguments.
+ *
+ * Result
+ * TRUE on success. 'reply' contains the result of the rpc
+ * FALSE on error. 'reply' will contain a description of the error
+ *
+ * In both cases, the caller should not free the reply.
+ *
+ * Side-effects
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+VSockOutSend(VSockOut *out, // IN
+ const char *request, // IN
+ size_t reqLen, // IN
+ const char **reply, // OUT
+ size_t *repLen) // OUT
+{
+ ASSERT(out);
+ ASSERT(out->fd != INVALID_SOCKET);
+
+ *reply = NULL;
+ *repLen = 0;
+
+ g_debug(LGPFX "Sending request for conn %d, reqLen=%d\n",
+ out->fd, (int)reqLen);
+
+ if (!Socket_SendPacket(out->fd, request, reqLen)) {
+ *reply = "VSockOut: Unable to send data for the RPCI command";
+ goto error;
+ }
+
+ free(out->payload);
+ out->payload = NULL;
+
+ if (!Socket_RecvPacket(out->fd, &out->payload, &out->payloadLen)) {
+ *reply = "VSockOut: Unable to receive the result of the RPCI command";
+ goto error;
+ }
+
+ if (out->payloadLen < 2 ||
+ ((out->payload[0] != '1') && (out->payload[0] != '0')) ||
+ out->payload[1] != ' ') {
+ *reply = "VSockOut: Invalid format for the result of the RPCI command";
+ goto error;
+ }
+
+ *reply = out->payload + 2;
+ *repLen = out->payloadLen - 2;
+
+ g_debug("VSockOut: recved %d bytes for conn %d\n", out->payloadLen, out->fd);
+
+ return out->payload[0] == '1';
+
+error:
+ *repLen = strlen(*reply);
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockChannelOnStartErr --
+ *
+ * Callback function to cleanup after channel start failure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VSockChannelOnStartErr(RpcChannel *chan) // IN
+{
+ VSockChannel *vsock = chan->_private;
+
+ /* destroy VSockOut part only */
+ VSockOutDestruct(vsock->out);
+ chan->_private = NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockChannelStart --
+ *
+ * Starts the RpcIn loop and the VSockOut channel.
+ *
+ * Results:
+ * TRUE on success.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+VSockChannelStart(RpcChannel *chan) // IN
+{
+ gboolean ret = TRUE;
+ VSockChannel *vsock = chan->_private;
+
+ ret = chan->in == NULL || chan->inStarted;
+
+ if (ret) {
+ ret = VSockOutStart(vsock->out);
+ if (!ret) {
+ if (chan->inStarted) {
+ RpcIn_stop(chan->in);
+ chan->inStarted = FALSE;
+ }
+ }
+ }
+ chan->outStarted = ret;
+
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockChannelStop --
+ *
+ * Stops a channel, keeping internal state so that it can be restarted
+ * later. It's safe to call this function more than once.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VSockChannelStop(RpcChannel *chan) // IN
+{
+ VSockChannel *vsock = chan->_private;
+
+ if (vsock->out != NULL) {
+ if (chan->outStarted) {
+ VSockOutStop(vsock->out);
+ }
+ chan->outStarted = FALSE;
+ } else {
+ ASSERT(!chan->outStarted);
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockChannelShutdown --
+ *
+ * Shuts down the Rpc channel.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VSockChannelShutdown(RpcChannel *chan) // IN
+{
+ VSockChannel *vsock = chan->_private;
+
+ VSockChannelStop(chan);
+ VSockOutDestruct(vsock->out);
+ g_free(vsock);
+ chan->_private = NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockChannelSend --
+ *
+ * Sends the data using the vsocket channel.
+ *
+ * Result:
+ * TRUE on success
+ * FALSE on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+VSockChannelSend(RpcChannel *chan, // IN
+ char const *data, // IN
+ size_t dataLen, // IN
+ char **result, // OUT
+ size_t *resultLen) // OUT
+{
+ gboolean ret = FALSE;
+ VSockChannel *vsock = chan->_private;
+ const char *reply;
+ size_t replyLen;
+
+ if (!chan->outStarted) {
+ goto exit;
+ }
+
+ ret = VSockOutSend(vsock->out, data, dataLen, &reply, &replyLen);
+
+ if (!ret) {
+ goto exit;
+ }
+
+ if (result != NULL) {
+ if (reply != NULL) {
+ *result = Util_SafeMalloc(replyLen + 1);
+ memcpy(*result, reply, replyLen);
+ (*result)[replyLen] = '\0';
+ } else {
+ *result = NULL;
+ }
+ }
+
+ if (resultLen != NULL) {
+ *resultLen = replyLen;
+ }
+
+exit:
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockChannel_GetType --
+ *
+ * Return the channel type that being used.
+ *
+ * Result:
+ * return the channel type.
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static RpcChannelType
+VSockChannelGetType(RpcChannel *chan)
+{
+ VSockChannel *vsock = chan->_private;
+
+ if (vsock->out != NULL) {
+ return vsock->out->type;
+ } else {
+ return RPCCHANNEL_TYPE_INACTIVE;
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockChannelStopRpcOut --
+ *
+ * Stop the RpcOut channel
+ *
+ * Result:
+ * return TRUE on success.
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+VSockChannelStopRpcOut(RpcChannel *chan)
+{
+ VSockChannel *vsock = chan->_private;
+ return VSockOutStop(vsock->out);
+}
+
+
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VSockChannel_New --
+ *
+ * Creates a new RpcChannel channel that uses the vsocket for
+ * communication.
+ *
+ * Result:
+ * return A new channel instance (never NULL).
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+RpcChannel *
+VSockChannel_New(void)
+{
+ RpcChannel *chan;
+ VSockChannel *vsock;
+
+ static RpcChannelFuncs funcs = {
+ VSockChannelStart,
+ VSockChannelStop,
+ VSockChannelSend,
+ NULL,
+ VSockChannelShutdown,
+ VSockChannelGetType,
+ VSockChannelOnStartErr,
+ VSockChannelStopRpcOut
+ };
+
+ chan = RpcChannel_Create();
+ vsock = g_malloc0(sizeof *vsock);
+
+ vsock->out = VSockOutConstruct();
+ ASSERT(vsock->out != NULL);
+
+ chan->inStarted = FALSE;
+ chan->outStarted = FALSE;
+
+ chan->_private = vsock;
+ chan->funcs = &funcs;
+
+ return chan;
+}
char *newBuf;
gboolean mapCreated = FALSE;
int64 pktType = (flags & RPCIN_TCLO_PING) ?
- RPCINPKT_TYPE_PING : RPCINPKT_TYPE_DATA;
+ GUESTRPCPKT_TYPE_PING : GUESTRPCPKT_TYPE_DATA;
res = DataMap_Create(&map);
if (res != DMERR_SUCCESS) {
}
mapCreated = TRUE;
- res = DataMap_SetInt64(&map, RPCINPKT_FIELD_TYPE,
+ res = DataMap_SetInt64(&map, GUESTRPCPKT_FIELD_TYPE,
pktType, TRUE);
if (res != DMERR_SUCCESS) {
goto quit;
goto quit;
}
memcpy(newBuf, buf, len);
- res = DataMap_SetString(&map, RPCINPKT_FIELD_PAYLOAD, newBuf,
+ res = DataMap_SetString(&map, GUESTRPCPKT_FIELD_PAYLOAD, newBuf,
len, TRUE);
if (res != DMERR_SUCCESS) {
+ free(newBuf);
goto quit;
}
}
return FALSE;
}
- res = DataMap_GetString(&map, RPCINPKT_FIELD_PAYLOAD, &buf, &len);
+ res = DataMap_GetString(&map, GUESTRPCPKT_FIELD_PAYLOAD, &buf, &len);
if (res == DMERR_SUCCESS) {
char *tmpPtr = (char *)malloc(len + 1);
if (tmpPtr == NULL) {
}
in->conn->in = in;
asock = AsyncSocket_ConnectVMCI(VMCI_HYPERVISOR_CONTEXT_ID,
- GUESTRPC_VSOCK_LISTEN_PORT,
+ GUESTRPC_TCLO_VSOCK_LISTEN_PORT,
RpcInConnectDone,
in->conn, 0, NULL, &res);
if (asock == NULL) {
/* shutdown rpc channel to free up VMCI/VSOCKET module usage */
if (ctx->rpc != NULL) {
- ASSERT(ctx->rpc->shutdown != NULL);
- ctx->rpc->shutdown(ctx->rpc);
+ RpcChannel_Shutdown(ctx->rpc);
ctx->rpc = NULL;
}
*/
static void
-ToolsCoreCheckReset(struct RpcChannel *chan,
+ToolsCoreCheckReset(RpcChannel *chan,
gboolean success,
gpointer _state)
{
state->name);
state->ctx.rpc = NULL;
} else {
- state->ctx.rpc = BackdoorChannel_New();
+ state->ctx.rpc = RpcChannel_New();
}
app = ToolsCore_GetTcloName(state);
if (app == NULL) {
libvmrpcdbg_la_CPPFLAGS += @CUNIT_CPPFLAGS@
libvmrpcdbg_la_CPPFLAGS += @GMODULE_CPPFLAGS@
libvmrpcdbg_la_CPPFLAGS += @VMTOOLS_CPPFLAGS@
+libvmrpcdbg_la_CPPFLAGS += -I$(top_builddir)/lib/rpcChannel
libvmrpcdbg_la_LDFLAGS =
libvmrpcdbg_la_LDFLAGS += @PLUGIN_LDFLAGS@
#include "strutil.h"
#include "util.h"
#include "vmrpcdbgInt.h"
+#include "rpcChannelInt.h"
#include "vmxrpc.h"
#include "xdrutil.h"
#include "vmware/tools/utils.h"
{
DbgChannelData *cdata;
RpcChannel *ret;
+ static RpcChannelFuncs funcs = {
+ RpcDebugStart,
+ RpcDebugStop,
+ RpcDebugSend,
+ RpcDebugSetup,
+ RpcDebugShutdown,
+ NULL,
+ NULL,
+ NULL
+ };
ASSERT(data != NULL);
ret = RpcChannel_Create();
- ret->start = RpcDebugStart;
- ret->stop = RpcDebugStop;
- ret->send = RpcDebugSend;
- ret->setup = RpcDebugSetup;
- ret->shutdown = RpcDebugShutdown;
+ ret->funcs = &funcs;
cdata = g_malloc0(sizeof *cdata);
cdata->plugin = data->debugPlugin;