/*********************************************************
- * Copyright (C) 2008,2014-2016,2018-2019 VMware, Inc. All rights reserved.
+ * Copyright (C) 2008,2014-2016,2018-2020 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
#if defined(__linux__) || defined(_WIN32)
RpcChannel *
-VSockChannel_New(void);
+VSockChannel_New(int flags);
#endif
void
/*********************************************************
- * Copyright (C) 2008-2016,2018-2019 VMware, Inc. All rights reserved.
+ * Copyright (C) 2008-2016,2018-2020 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
/**
- * Create an RpcChannel instance using a prefered channel implementation,
+ * Create a one-off RpcChannel instance using a prefered channel implementation,
* currently this is VSockChannel.
*
* @return RpcChannel
*/
-RpcChannel *
-RpcChannel_New(void)
+static RpcChannel *
+RpcChannel_NewOne(int flags)
{
RpcChannel *chan;
#if (defined(__linux__) && !defined(USERWORLD)) || defined(_WIN32)
chan = (gUseBackdoorOnly || gVSocketFailed) ?
- BackdoorChannel_New() : VSockChannel_New();
+ BackdoorChannel_New() : VSockChannel_New(flags);
#else
chan = BackdoorChannel_New();
#endif
}
+/**
+ * Create an RpcChannel instance using a prefered channel implementation,
+ * currently this is VSockChannel.
+ *
+ * @return RpcChannel
+ */
+
+RpcChannel *
+RpcChannel_New(void)
+{
+ return RpcChannel_NewOne(0);
+}
+
+
/**
* Start an RPC channel. We may fallback to backdoor channel when other type
* of channel fails to start.
{
RpcChannel *chan;
gboolean status = FALSE;
+ int flags;
+ flags = RPCCHANNEL_FLAGS_SEND_ONE;
#if (defined(__linux__) && !defined(USERWORLD)) || defined(_WIN32)
- chan = priv ? VSockChannel_New() : RpcChannel_New();
+ flags |= RPCCHANNEL_FLAGS_FAST_CLOSE;
+ chan = priv ? VSockChannel_New(flags) : RpcChannel_NewOne(flags);
#else
- chan = RpcChannel_New();
+ chan = RpcChannel_NewOne(flags);
#endif
if (chan == NULL) {
/*********************************************************
- * Copyright (C) 2008-2016,2018-2019 VMware, Inc. All rights reserved.
+ * Copyright (C) 2008-2016,2018-2020 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
struct RpcIn;
#endif
+/*
+ * Flags associated with the RPC Channel
+ */
+
+/* Channel will be usaed for a single RPC */
+#define RPCCHANNEL_FLAGS_SEND_ONE 0x1
+/* VMX should close channel after sending reply */
+#define RPCCHANNEL_FLAGS_FAST_CLOSE 0x2
+
/** a list of interface functions for a channel implementation */
typedef struct _RpcChannelFuncs{
gboolean (*start)(RpcChannel *);
/*********************************************************
- * Copyright (C) 2013-2017,2019 VMware, Inc. All rights reserved.
+ * Copyright (C) 2013-2017,2019-2020 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
/* We are required to use a privileged source port. */
localPort = PRIVILEGED_PORT_MAX;
while (localPort >= PRIVILEGED_PORT_MIN) {
+ int retryCount = 0;
+
fd = SocketConnectVmciInternal(&addr, localPort, &apiErr, &sysErr);
if (fd != INVALID_SOCKET) {
goto done;
*/
continue;
}
+
+ if (apiErr == SOCKERR_CONNECT && sysErr == SYSERR_ENOBUFS) {
+ /*
+ * ENOBUFS can happen if we're out of vsocks in the kernel.
+ * Delay a bit and try again using the same port.
+ * Have a retry count in case something has gone horribly wrong.
+ */
+ if (++retryCount > 5) {
+ goto done;
+ }
+#ifdef _WIN32
+ Sleep(1);
+#else
+ usleep(1000);
+#endif
+ continue;
+ }
/* Unrecoverable error occurred */
goto done;
}
static gboolean
Socket_PackSendData(const char *buf, // IN
int len, // IN
+ Bool fastClose, // IN
char **serBuf, // OUT
int32 *serBufLen) // OUT
{
goto error;
}
+ if (fastClose) {
+ res = DataMap_SetInt64(&map, GUESTRPCPKT_FIELD_FAST_CLOSE, TRUE, TRUE);
+ if (res != DMERR_SUCCESS) {
+ goto error;
+ }
+ }
+
res = DataMap_Serialize(&map, serBuf, serBufLen);
if (res != DMERR_SUCCESS) {
goto error;
gboolean
Socket_SendPacket(SOCKET sock, // IN
const char *payload, // IN
- int payloadLen) // IN
+ int payloadLen, // IN
+ Bool fastClose) // IN
{
gboolean ok;
char *sendBuf;
int sendBufLen;
- if (!Socket_PackSendData(payload, payloadLen, &sendBuf, &sendBufLen)) {
+ if (!Socket_PackSendData(payload, payloadLen, fastClose,
+ &sendBuf, &sendBufLen)) {
return FALSE;
}
/*********************************************************
- * Copyright (C) 2013-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2013-2016,2020 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
#define SYSERR_EACCESS WSAEACCES
#define SYSERR_EINTR WSAEINTR
#define SYSERR_ECONNRESET WSAECONNRESET
+#define SYSERR_ENOBUFS WSAENOBUFS
typedef int socklen_t;
#define SYSERR_EACCESS EACCES
#define SYSERR_EINTR EINTR
#define SYSERR_ECONNRESET ECONNRESET
+#define SYSERR_ENOBUFS ENOBUFS
typedef int SOCKET;
#define SOCKET_ERROR (-1)
int *payloadLen);
gboolean Socket_SendPacket(SOCKET sock,
const char *payload,
- int payloadLen);
+ int payloadLen,
+ Bool fastClose);
#endif /* _SIMPLESOCKET_H_ */
/*********************************************************
- * Copyright (C) 2013-2016,2018-2019 VMware, Inc. All rights reserved.
+ * Copyright (C) 2013-2016,2018-2020 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
char *payload;
int payloadLen;
RpcChannelType type;
+ int flags;
} VSockOut;
typedef struct VSockChannel {
*/
static VSockOut *
-VSockOutConstruct(void)
+VSockOutConstruct(int flags)
{
VSockOut *out = calloc(1, sizeof *out);
if (out != NULL) {
out->fd = INVALID_SOCKET;
out->type = RPCCHANNEL_TYPE_INACTIVE;
+ out->flags = flags;
}
return out;
}
Debug(LGPFX "Sending request for conn %d, reqLen=%d\n",
out->fd, (int)reqLen);
- if (!Socket_SendPacket(out->fd, request, reqLen)) {
+ if (!Socket_SendPacket(out->fd, request, reqLen,
+ (out->flags & RPCCHANNEL_FLAGS_FAST_CLOSE))) {
*reply = "VSockOut: Unable to send data for the RPCI command";
goto error;
}
*/
RpcChannel *
-VSockChannel_New(void)
+VSockChannel_New(int flags)
{
RpcChannel *chan;
VSockChannel *vsock;
chan = RpcChannel_Create();
vsock = g_malloc0(sizeof *vsock);
- vsock->out = VSockOutConstruct();
+ vsock->out = VSockOutConstruct(flags);
ASSERT(vsock->out != NULL);
#if defined(NEED_RPCIN)