#include "msg.h"
#include "posix.h"
#include "vmci_sockets.h"
+#ifndef VMX86_TOOLS
+#include "vmdblib.h"
+#endif
#define LOGLEVEL_MODULE asyncsocket
#include "loglevel_user.h"
static void AsyncSocketAcceptCallback(void *clientData);
static void AsyncSocketConnectCallback(void *clientData);
static void AsyncSocketRecvUDPCallback(void *clientData);
-static void AsyncSocketSendCallback(void *clientData);
static int AsyncSocketBlockingWork(AsyncSocket *asock, Bool read, void *buf, int len,
int *completed, int timeoutMS, Bool partial);
static VMwareStatus AsyncSocketPollAdd(AsyncSocket *asock, Bool socket,
static Bool AsyncSocketHasDataPendingSocket(AsyncSocket *asock);
static void AsyncSocketReleaseSocket(AsyncSocket *s);
+static VMwareStatus AsyncSocketIPollAdd(AsyncSocket *asock, Bool socket,
+ int flags, PollerFunction callback,
+ int info);
+static Bool AsyncSocketIPollRemove(AsyncSocket *asock, Bool socket, int flags,
+ PollerFunction callback);
+static void AsyncSocketIPollSendCallback(void *clientData);
+static void AsyncSocketIPollRecvCallback(void *clientData);
+
static const AsyncSocketVTable asyncStreamSocketVTable = {
AsyncSocketDispatchConnect,
AsyncSocketSendInternal,
AsyncSocketSendSocket,
AsyncSocketRecvSocket,
+ AsyncSocketSendCallback,
AsyncSocketRecvCallback,
AsyncSocketHasDataPendingSocket,
AsyncSocketCancelListenCbSocket,
AsyncSocketSendInternal,
AsyncSocketSendSocket,
AsyncSocketRecvSocket,
+ AsyncSocketSendCallback,
AsyncSocketRecvUDPCallback,
AsyncSocketHasDataPendingSocket,
AsyncSocketCancelListenCbSocket,
};
+static const AsyncSocketVTable asyncStreamSocketIPollVTable = {
+ AsyncSocketDispatchConnect,
+ AsyncSocketSendInternal,
+ AsyncSocketSendSocket,
+ AsyncSocketRecvSocket,
+ AsyncSocketIPollSendCallback,
+ AsyncSocketIPollRecvCallback,
+ AsyncSocketHasDataPendingSocket,
+ AsyncSocketCancelListenCbSocket,
+ AsyncSocketCancelRecvCbSocket,
+ AsyncSocketCancelCbForCloseSocket,
+ AsyncSocketCancelCbForConnectingCloseSocket,
+ AsyncSocketCloseSocket,
+ AsyncSocketReleaseSocket,
+};
+
+
/*
*----------------------------------------------------------------------------
*
s->pollParams.pollClass = POLL_CS_MAIN;
s->pollParams.flags = 0;
s->pollParams.lock = NULL;
+ s->pollParams.iPoll = NULL;
}
return s;
s->fd = fd;
s->type = SOCK_STREAM;
s->asockType = ASYNCSOCKET_TYPE_SOCKET;
- s->vt = &asyncStreamSocketVTable;
+ if (s->pollParams.iPoll == NULL) {
+ s->vt = &asyncStreamSocketVTable;
+ } else {
+ s->vt = &asyncStreamSocketIPollVTable;
+ }
/* From now on socket is ours. */
SSL_SetCloseOnShutdownFlag(sslSock);
* already make 0-byte send() to force WSAEWOULDBLOCK.
*/
- if (AsyncSocketPollAdd(asock, FALSE, 0, AsyncSocketSendCallback, 0)
+ if (AsyncSocketPollAdd(asock, FALSE, 0, asock->vt->sendCallback, 0)
!= VMWARE_STATUS_SUCCESS) {
retVal = ASOCKERR_POLL;
return retVal;
*/
if (AsyncSocketPollAdd(asock, TRUE, POLL_FLAG_WRITE,
- AsyncSocketSendCallback)
+ asock->vt->sendCallback)
!= VMWARE_STATUS_SUCCESS) {
retVal = ASOCKERR_POLL;
return retVal;
*/
if (s->state == AsyncSocketConnecting) {
removed = AsyncSocketPollRemove(s, TRUE, POLL_FLAG_WRITE,
- AsyncSocketConnectCallback)
+ AsyncSocketConnectCallback)
|| AsyncSocketPollRemove(s, FALSE, 0, AsyncSocketConnectCallback);
ASSERT(removed);
}
removed = AsyncSocketPollRemove(s, TRUE,
POLL_FLAG_READ | POLL_FLAG_PERIODIC,
s->vt->recvCallback);
- ASSERT(removed);
+ ASSERT(removed || s->pollParams.iPoll);
s->inBlockingRecv++;
AsyncSocketUnlock(s); /* We may sleep in poll. */
removed = AsyncSocketPollRemove(asock, TRUE,
POLL_FLAG_READ | POLL_FLAG_PERIODIC,
asock->vt->recvCallback);
- ASSERT_NOT_IMPLEMENTED(removed);
+ ASSERT_NOT_IMPLEMENTED(removed || asock->pollParams.iPoll);
asock->recvCb = FALSE;
}
}
* Callback might be temporarily removed in AsyncSocket_DoOneMsg.
*/
- ASSERT_NOT_TESTED(removed);
+ ASSERT_NOT_TESTED(removed || asock->pollParams.iPoll);
/*
* We may still have the RTime callback, try to remove if it exists
*/
removed = AsyncSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE,
- AsyncSocketSendCallback)
- || AsyncSocketPollRemove(asock, FALSE, 0, AsyncSocketSendCallback);
- ASSERT(removed);
+ asock->vt->sendCallback)
+ || AsyncSocketPollRemove(asock, FALSE, 0, asock->vt->sendCallback);
+ ASSERT(removed || asock->pollParams.iPoll);
asock->sendCb = FALSE;
}
}
ASSERT(asock);
ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE);
+ ASSERT(asock->pollParams.iPoll == NULL);
ASSERT(AsyncSocketIsLocked(asock));
AsyncSocketAddRef(asock);
ASSERT(asock);
ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE);
+ ASSERT(asock->pollParams.iPoll == NULL);
ASSERT(AsyncSocketIsLocked(asock));
AsyncSocketAddRef(asock);
}
+/*
+ *----------------------------------------------------------------------------
+ *
+ * AsyncSocketIPollRecvCallback --
+ *
+ * Poll callback for input waiting on the socket. IVmdbPoll does not
+ * handle callback locks, so this function first locks the asyncsocket
+ * and verify that the recv callback has not been cancelled before
+ * calling AsyncSocketFillRecvBuffer to do the real work.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Reads data, could fire recv completion or trigger socket destruction.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+AsyncSocketIPollRecvCallback(void *clientData) // IN:
+{
+#ifdef VMX86_TOOLS
+ NOT_IMPLEMENTED();
+#else
+ AsyncSocket *asock = (AsyncSocket *) clientData;
+ int error;
+
+ ASSERT(asock);
+ ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE);
+ ASSERT(asock->pollParams.lock == NULL ||
+ !MXUser_IsCurThreadHoldingRecLock(asock->pollParams.lock));
+
+ AsyncSocketLock(asock);
+ if (!asock->recvCb) {
+ MXUserRecLock *lock = asock->pollParams.lock;
+
+ /* Release the reference added when registering this callback. */
+ AsyncSocketRelease(asock, TRUE);
+ if (lock != NULL) {
+ MXUser_DecRefRecLock(lock);
+ }
+ return;
+ }
+
+ AsyncSocketAddRef(asock);
+
+ error = AsyncSocketFillRecvBuffer(asock);
+ if (error == ASOCKERR_GENERIC || error == ASOCKERR_REMOTE_DISCONNECT) {
+ AsyncSocketHandleError(asock, error);
+ }
+
+ AsyncSocketRelease(asock, TRUE);
+#endif
+}
+
+
/*
*----------------------------------------------------------------------------
*
*----------------------------------------------------------------------------
*/
-static void
+void
AsyncSocketSendCallback(void *clientData)
{
AsyncSocket *s = (AsyncSocket *) clientData;
if (!s->sslConnected) {
pollStatus = AsyncSocketPollAdd(s, FALSE, 0,
- AsyncSocketSendCallback, 100000);
+ s->vt->sendCallback, 100000);
ASSERT_NOT_IMPLEMENTED(pollStatus == VMWARE_STATUS_SUCCESS);
} else
#endif
{
pollStatus = AsyncSocketPollAdd(s, TRUE, POLL_FLAG_WRITE,
- AsyncSocketSendCallback);
+ s->vt->sendCallback);
ASSERT_NOT_IMPLEMENTED(pollStatus == VMWARE_STATUS_SUCCESS);
}
s->sendCb = TRUE;
}
+/*
+ *----------------------------------------------------------------------------
+ *
+ * AsyncSocketIPollSendCallback --
+ *
+ * IVmdbPoll callback for output socket buffer space available. IVmdbPoll
+ * does not handle callback locks, so this function first locks the
+ * asyncsocket and verify that the send callback has not been cancelled.
+ * IVmdbPoll only has periodic callbacks, so this function unregisters
+ * itself before calling AsyncSocketSendCallback to do the real work.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Writes data, could trigger write completion or socket destruction.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+AsyncSocketIPollSendCallback(void *clientData) // IN:
+{
+#ifdef VMX86_TOOLS
+ NOT_IMPLEMENTED();
+#else
+ AsyncSocket *s = (AsyncSocket *) clientData;
+ Bool removed;
+
+ ASSERT(s);
+ ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE);
+
+ AsyncSocketLock(s);
+ if (!s->sendCb) {
+ MXUserRecLock *lock = s->pollParams.lock;
+
+ /* Release the reference added when registering this callback. */
+ AsyncSocketRelease(s, TRUE);
+ if (lock != NULL) {
+ MXUser_DecRefRecLock(lock);
+ }
+ return;
+ }
+
+ AsyncSocketAddRef(s);
+
+ /* Unregister this callback as we want the non-periodic behavior. */
+ removed = AsyncSocketIPollRemove(s, TRUE, POLL_FLAG_WRITE,
+ AsyncSocketIPollSendCallback) ||
+ AsyncSocketIPollRemove(s, FALSE, 0, AsyncSocketIPollSendCallback);
+
+ AsyncSocketSendCallback(s);
+
+ AsyncSocketRelease(s, TRUE);
+#endif
+}
+
+
/*
*-----------------------------------------------------------------------------
*
va_end(marker);
}
+ if (asock->pollParams.iPoll != NULL) {
+ return AsyncSocketIPollAdd(asock, socket, flags, callback, info);
+ }
+
return Poll_Callback(asock->pollParams.pollClass,
flags | asock->pollParams.flags,
callback, asock, type, info,
ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE);
+ if (asock->pollParams.iPoll != NULL) {
+ return AsyncSocketIPollRemove(asock, socket, flags, callback);
+ }
+
if (socket) {
type = POLL_DEVICE;
flags |= POLL_FLAG_SOCKET;
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * AsyncSocketIPollAdd --
+ *
+ * Add a poll callback. Wrapper for IVmdbPoll.Register[Timer].
+ *
+ * If socket is FALSE, user has to pass in the timeout value
+ *
+ * Results:
+ * VMwareStatus result code.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VMwareStatus
+AsyncSocketIPollAdd(AsyncSocket *asock,
+ Bool socket,
+ int flags,
+ PollerFunction callback,
+ int info)
+{
+#ifdef VMX86_TOOLS
+ return VMWARE_STATUS_ERROR;
+#else
+ VMwareStatus status = VMWARE_STATUS_SUCCESS;
+ VmdbRet ret;
+ IVmdbPoll *poll;
+
+ ASSERT(asock->pollParams.iPoll);
+ ASSERT(AsyncSocketIsLocked(asock));
+
+ /* Protect asyncsocket and lock from disappearing */
+ AsyncSocketAddRef(asock);
+ if (asock->pollParams.lock != NULL) {
+ MXUser_IncRefRecLock(asock->pollParams.lock);
+ }
+
+ poll = asock->pollParams.iPoll;
+
+ if (socket) {
+ int pollFlags = (flags & POLL_FLAG_READ) != 0 ? VMDB_PRF_READ
+ : VMDB_PRF_WRITE;
+
+ ret = poll->Register(poll, pollFlags, callback, asock, info);
+ } else {
+ ret = poll->RegisterTimer(poll, callback, asock, info);
+ }
+
+ if (ret != VMDB_S_OK) {
+ Log(ASOCKPREFIX "failed to register callback (%s %d): error %d\n",
+ socket ? "socket" : "delay", info, ret);
+ if (asock->pollParams.lock != NULL) {
+ MXUser_DecRefRecLock(asock->pollParams.lock);
+ }
+ AsyncSocketRelease(asock, FALSE);
+ status = VMWARE_STATUS_ERROR;
+ }
+
+ return status;
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * AsyncSocketIPollRemove --
+ *
+ * Remove a poll callback. Wrapper for IVmdbPoll.Unregister[Timer].
+ *
+ * Results:
+ * TRUE if the callback was registered and has been cancelled successfully.
+ * FALSE if the callback was not registered, or the callback is already
+ * scheduled to fire (and is guaranteed to fire).
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+AsyncSocketIPollRemove(AsyncSocket *asock,
+ Bool socket,
+ int flags,
+ PollerFunction callback)
+{
+#ifdef VMX86_TOOLS
+ return FALSE;
+#else
+ IVmdbPoll *poll;
+ Bool ret;
+
+ ASSERT(asock->pollParams.iPoll);
+ ASSERT(AsyncSocketIsLocked(asock));
+
+ poll = asock->pollParams.iPoll;
+
+ if (socket) {
+ int pollFlags = (flags & POLL_FLAG_READ) != 0 ? VMDB_PRF_READ
+ : VMDB_PRF_WRITE;
+
+ ret = poll->Unregister(poll, pollFlags, callback, asock);
+ } else {
+ ret = poll->UnregisterTimer(poll, callback, asock);
+ }
+
+ if (ret) {
+ MXUserRecLock *lock = asock->pollParams.lock;
+
+ /* Release the reference taken when registering the callback. */
+ AsyncSocketRelease(asock, FALSE);
+ if (lock != NULL) {
+ MXUser_DecRefRecLock(lock);
+ }
+ }
+
+ return ret;
+#endif
+}
+
+
+
+
/*
*-----------------------------------------------------------------------------
*
VMwareStatus pollStatus;
ASSERT(asock);
+ ASSERT(asock->pollParams.iPoll == NULL);
ASSERT(AsyncSocketIsLocked(asock));
AsyncSocketAddRef(asock);
#if CAN_USE_FTS
# include <fts.h>
-struct WalkDirContextImpl
-{
+struct WalkDirContextImpl {
FTS *fts;
};
#define FS_NFS_ON_ESX "NFS"
/* A string for VMFS on ESX file system type */
#define FS_VMFS_ON_ESX "VMFS"
+#define FS_VSAN_URI_PREFIX "vsan:"
#if defined __ANDROID__
/*
*
* File_UnlinkDelayed --
*
- * Same as File_Unlink for POSIX systems since we can unlink anytime.
+ * Same as File_Unlink for POSIX systems since we can unlink anytime.
*
* Results:
- * Return 0 if the unlink is successful. Otherwise, returns -1.
+ * Return 0 if the unlink is successful. Otherwise, returns -1.
*
* Side effects:
- * None.
+ * None.
*
*-----------------------------------------------------------------------------
*/
*
* File_GetVMFSAttributes --
*
- * Acquire the attributes for a given file on a VMFS volume.
+ * Acquire the attributes for a given file or directory on a VMFS volume.
*
* Results:
* Integer return value and populated FS_PartitionListResult
*/
int
-File_GetVMFSAttributes(ConstUnicode pathName, // IN: File to test
+File_GetVMFSAttributes(ConstUnicode pathName, // IN: File/dir to test
FS_PartitionListResult **fsAttrs) // IN/OUT: VMFS Info
{
int fd;
int ret;
Unicode fullPath;
-
- Unicode parentPath = NULL;
+ Unicode directory = NULL;
fullPath = File_FullPath(pathName);
if (fullPath == NULL) {
goto bail;
}
- File_SplitName(fullPath, NULL, &parentPath, NULL);
+ if (File_IsDirectory(fullPath)) {
+ directory = Unicode_Duplicate(fullPath);
+ } else {
+ File_SplitName(fullPath, NULL, &directory, NULL);
+ }
if (!HostType_OSIsVMK()) {
Log(LGPFX" %s: File %s not on VMFS volume\n", __func__, UTF8(pathName));
(*fsAttrs)->ioctlAttr.maxPartitions = FS_PLIST_DEF_MAX_PARTITIONS;
(*fsAttrs)->ioctlAttr.getAttrSpec = FS_ATTR_SPEC_BASIC;
- fd = Posix_Open(parentPath, O_RDONLY, 0);
+ fd = Posix_Open(directory, O_RDONLY, 0);
if (fd == -1) {
Log(LGPFX" %s: could not open %s: %s\n", __func__, UTF8(pathName),
bail:
Unicode_Free(fullPath);
- Unicode_Free(parentPath);
+ Unicode_Free(directory);
return ret;
}
if (memcmp(fsAttrs->fsType, FS_NFS_ON_ESX, sizeof(FS_NFS_ON_ESX)) == 0) {
/*
* logicalDevice from NFS3 client contains remote IP and remote
- * mount point, separate by space. Split them out. If there is
+ * mount point, separated by space. Split them out. If there is
* no space then this is probably NFS41 client, and we cannot
* obtain its remote mount point details at this time.
*/
char *
File_GetUniqueFileSystemID(char const *path) // IN: File path
{
- if (HostType_OSIsVMK()) {
- char *canPath;
- char *existPath;
-
- existPath = FilePosixNearestExistingAncestor(path);
- canPath = Posix_RealPath(existPath);
- free(existPath);
-
- if (canPath == NULL) {
- return NULL;
- }
+#ifdef VMX86_SERVER
+ char vmfsVolumeName[FILE_MAXPATH];
+ char *existPath;
+ char *canPath;
- /*
- * VCFS doesn't have real mount points, so the mount point lookup below
- * returns "/vmfs", instead of the VCFS mount point.
- *
- * See bug 61646 for why we care.
- */
+ existPath = FilePosixNearestExistingAncestor(path);
+ canPath = Posix_RealPath(existPath);
+ free(existPath);
- if (strncmp(canPath, VCFS_MOUNT_POINT, strlen(VCFS_MOUNT_POINT)) == 0) {
- char vmfsVolumeName[FILE_MAXPATH];
+ if (canPath == NULL) {
+ return NULL;
+ }
- if (sscanf(canPath, VCFS_MOUNT_PATH "%[^/]%*s",
- vmfsVolumeName) == 1) {
- free(canPath);
+ /*
+ * VCFS doesn't have real mount points, so the mount point lookup below
+ * returns "/vmfs", instead of the VCFS mount point.
+ *
+ * See bug 61646 for why we care.
+ */
+ if (strncmp(canPath, VCFS_MOUNT_POINT, strlen(VCFS_MOUNT_POINT)) != 0 ||
+ sscanf(canPath, VCFS_MOUNT_PATH "%[^/]%*s", vmfsVolumeName) != 1) {
+ free(canPath);
+ goto exit;
+ }
- return Str_SafeAsprintf(NULL, "%s/%s", VCFS_MOUNT_POINT,
- vmfsVolumeName);
- }
+ /*
+ * If the path points to a file or directory that is on a vsan datastore,
+ * we have to determine which namespace object is involved.
+ */
+ if (strncmp(vmfsVolumeName, FS_VSAN_URI_PREFIX,
+ strlen(FS_VSAN_URI_PREFIX)) == 0) {
+ FS_PartitionListResult *fsAttrs = NULL;
+ int res;
+
+ res = File_GetVMFSAttributes(canPath, &fsAttrs);
+
+ if (res >= 0 && fsAttrs != NULL &&
+ strncmp(fsAttrs->fsType, FS_VMFS_ON_ESX,
+ strlen(FS_VMFS_ON_ESX)) == 0) {
+ char *unique;
+ unique = Str_SafeAsprintf(NULL, "%s/%s/%s",
+ VCFS_MOUNT_POINT, vmfsVolumeName,
+ fsAttrs->name);
+ free(fsAttrs);
+ free(canPath);
+ return unique;
}
-
- free(canPath);
+ free(fsAttrs);
}
+ free(canPath);
+ return Str_SafeAsprintf(NULL, "%s/%s", VCFS_MOUNT_POINT,
+ vmfsVolumeName);
+exit:
+#endif
return FilePosixGetBlockDevice(path);
}
File_Replace(ConstUnicode oldName, // IN: old file
ConstUnicode newName) // IN: new file
{
- int status;
+ int status = 0;
Bool result = FALSE;
char *newPath = NULL;
char *oldPath = NULL;
goto bail;
}
- status = (rename(newPath, oldPath) == -1) ? errno : 0;
- if (status != 0) {
+
+ if (rename(newPath, oldPath) < 0) {
+ status = errno;
Msg_Append(MSGID(filePosix.replaceRenameFailed)
"Failed to rename \"%s\" to \"%s\": %s\n",
newName, oldName, Msg_ErrString());
*
* File_MakeCfgFileExecutable --
*
- * Make a .vmx file executable. This is sometimes necessary
+ * Make a .vmx file executable. This is sometimes necessary
* to enable MKS access to the VM.
*
* Owner always gets rwx. Group/other get x where r is set.