From: John Wolfe Date: Thu, 8 Sep 2022 21:51:39 +0000 (-0700) Subject: Common source file changes not applicable to open-vm-tools. X-Git-Tag: stable-12.2.0~123 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=365db99d442774c49234ae157fc4373d0bb6c4f8;p=thirdparty%2Fopen-vm-tools.git Common source file changes not applicable to open-vm-tools. --- diff --git a/open-vm-tools/lib/asyncsocket/asyncSocketBase.c b/open-vm-tools/lib/asyncsocket/asyncSocketBase.c index f8e0cbbbf..6d9674b54 100644 --- a/open-vm-tools/lib/asyncsocket/asyncSocketBase.c +++ b/open-vm-tools/lib/asyncsocket/asyncSocketBase.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2016-2021 VMware, Inc. All rights reserved. + * Copyright (C) 2016-2022 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 @@ -627,7 +627,8 @@ AsyncSocketSetRecvBuf(AsyncSocket *asock, // IN: return ASOCKERR_INVAL; } - if (AsyncSocketGetState(asock) != AsyncSocketConnected) { + if (AsyncSocketGetState(asock) != AsyncSocketConnected && + AsyncSocketGetState(asock) != AsyncSocketConnectedRdOnly) { ASOCKWARN(asock, "recv called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } diff --git a/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c b/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c index 8a532b3e0..93d1de6df 100644 --- a/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c +++ b/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2016-2021 VMware, Inc. All rights reserved. + * Copyright (C) 2016-2022 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 @@ -1259,6 +1259,48 @@ AsyncSocket_Close(AsyncSocket *asock) // IN } +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_CloseWrite -- + * + * Close the write side of AsyncSocket, and leave the read side open. This + * can be used to implement a shutdown(SHUT_WR...) equivalent. + * + * This function is meant to be called after the socket has been connected + * If no error, pending send is flushed the same way as AsyncSocket_Close, + * and then the socket enters half-closed state, disallowing further send. + * + * Like AsyncSocket_Close, it's safe to call at any time, but it could err + * when the socket is not connected. Unlike Close, read side of the socket + * is left intact, and the the socket is not released. + * + * If the socket is already closed, it returns success. + * + * Results: + * ASOCKERR_*. + * + * Side effects: + * Send is not permitted after this call. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_CloseWrite(AsyncSocket *asock) // IN +{ + int ret; + if (VALID(asock, closeWrite)) { + AsyncSocketLock(asock); + ret = VT(asock)->closeWrite(asock); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; +} + + /* *----------------------------------------------------------------------------- * diff --git a/open-vm-tools/lib/asyncsocket/asyncSocketVTable.h b/open-vm-tools/lib/asyncsocket/asyncSocketVTable.h index c068ff505..91307f5b7 100644 --- a/open-vm-tools/lib/asyncsocket/asyncSocketVTable.h +++ b/open-vm-tools/lib/asyncsocket/asyncSocketVTable.h @@ -109,6 +109,7 @@ typedef struct AsyncSocketVTable { int (*getNetworkStats)(AsyncSocket *asock, AsyncSocketNetworkStats *stats); int (*close)(AsyncSocket *asock); + int (*closeWrite)(AsyncSocket *asock); int (*cancelRecv)(AsyncSocket *asock, int *partialRecvd, void **recvBuf, void **recvFn, Bool cancelOnSend); int (*cancelCbForClose)(AsyncSocket *asock); diff --git a/open-vm-tools/lib/asyncsocket/asyncsocket.c b/open-vm-tools/lib/asyncsocket/asyncsocket.c index 2bf97b549..6053a3bdb 100644 --- a/open-vm-tools/lib/asyncsocket/asyncsocket.c +++ b/open-vm-tools/lib/asyncsocket/asyncsocket.c @@ -336,6 +336,7 @@ static int AsyncTCPSocketStartSslAccept(AsyncSocket *asock, void *sslCtx, void *clientData); static int AsyncTCPSocketFlush(AsyncSocket *asock, int timeoutMS); static void AsyncTCPSocketCancelRecvCb(AsyncTCPSocket *asock); +static void AsyncTCPSocketCancelSendCb(AsyncTCPSocket *asock); static int AsyncTCPSocketRecv(AsyncSocket *asock, void *buf, int len, Bool partial, void *cb, void *cbData); @@ -351,6 +352,7 @@ static int AsyncTCPSocketSendWithFd(AsyncSocket *asock, void *buf, int len, void *clientData); static int AsyncTCPSocketIsSendBufferFull(AsyncSocket *asock); static int AsyncTCPSocketClose(AsyncSocket *asock); +static int AsyncTCPSocketCloseWrite(AsyncSocket *asock); static int AsyncTCPSocketCancelRecv(AsyncSocket *asock, int *partialRecvd, void **recvBuf, void **recvFn, Bool cancelOnSend); @@ -412,6 +414,7 @@ static const AsyncSocketVTable asyncTCPSocketVTable = { AsyncTCPSocketIsSendBufferFull, NULL, /* getNetworkStats */ AsyncTCPSocketClose, + AsyncTCPSocketCloseWrite, AsyncTCPSocketCancelRecv, AsyncTCPSocketCancelCbForClose, AsyncTCPSocketGetLocalVMCIAddress, @@ -736,7 +739,8 @@ AsyncTCPSocketGetRemoteIPStr(AsyncSocket *base, // IN ASSERT(ipRetStr != NULL); if (ipRetStr == NULL || asock == NULL || - AsyncTCPSocketGetState(asock) != AsyncSocketConnected || + (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && + AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) || (asock->remoteAddrLen != sizeof (struct sockaddr_in) && asock->remoteAddrLen != sizeof (struct sockaddr_in6))) { ret = ASOCKERR_GENERIC; @@ -784,7 +788,8 @@ AsyncTCPSocketGetRemotePort(AsyncSocket *base, // IN ASSERT(asock); if (asock == NULL || - AsyncTCPSocketGetState(asock) != AsyncSocketConnected || + (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && + AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) || (asock->remoteAddrLen != sizeof(struct sockaddr_in) && asock->remoteAddrLen != sizeof(struct sockaddr_in6))) { ret = ASOCKERR_GENERIC; @@ -2625,7 +2630,8 @@ AsyncTCPSocketRecv(AsyncSocket *base, // IN: ASSERT(AsyncTCPSocketIsLocked(asock)); - if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && + AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) { TCPSOCKWARN(asock, "recv called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } @@ -2761,7 +2767,8 @@ AsyncTCPSocketPeek(AsyncSocket *base, // IN: return ASOCKERR_INVAL; } - if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && + AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) { TCPSOCKWARN(asock, "peek called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } @@ -3206,7 +3213,9 @@ AsyncTCPSocketBlockingWork(AsyncTCPSocket *s, // IN: return ASOCKERR_INVAL; } - if (AsyncTCPSocketGetState(s) != AsyncSocketConnected) { + if (AsyncTCPSocketGetState(s) != AsyncSocketConnected && + /* Allow AsyncSocketConnectedRdOnly iff we are reading */ + (AsyncTCPSocketGetState(s) != AsyncSocketConnectedRdOnly || !read)) { TCPSOCKWARN(s, "recv called but state is not connected!\n"); return ASOCKERR_NOTCONNECTED; } @@ -3654,7 +3663,8 @@ AsyncTCPSocketFillRecvBuffer(AsyncTCPSocket *s) // IN int pending = 0; ASSERT(AsyncTCPSocketIsLocked(s)); - ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || + AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); /* * When a socket has received all its desired content and FillRecvBuffer is @@ -3715,10 +3725,10 @@ AsyncTCPSocketFillRecvBuffer(AsyncTCPSocket *s) // IN goto exit; } } else if (recvd == 0) { - TCPSOCKLG0(s, "recv detected client closed connection\n"); + TCPSOCKLG0(s, "recv detected remote shutdown\n"); /* - * We treat this as an error so that the owner can detect closing - * of connection by peer (via the error handler callback). + * We treat this as an error so that the owner can detect orderly + * shutdown (or half-close) by peer (via the error handler callback). */ result = ASOCKERR_REMOTE_DISCONNECT; goto exit; @@ -3819,7 +3829,8 @@ AsyncTCPSocketFillPeekBuffer(AsyncTCPSocket *s, // IN #define MAX_NESTED_PEEKS 8 ASSERT(AsyncTCPSocketIsLocked(s)); - ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || + AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); ASSERT(s->flags & ASOCK_FLAG_PEEK); needed = s->base.recvLen - s->base.recvPos; @@ -3854,10 +3865,10 @@ AsyncTCPSocketFillPeekBuffer(AsyncTCPSocket *s, // IN } ASSERT(s->base.recvPos == 0); } else if (recvd == 0) { - TCPSOCKLG0(s, "peek detected client closed connection\n"); + TCPSOCKLG0(s, "peek detected remote shutdown\n"); /* - * We treat this as an error so that the owner can detect closing - * of connection by peer (via the error handler callback). + * We treat this as an error so that the owner can detect orderly + * shutdown (or half-close) by peer (via the error handler callback). */ result = ASOCKERR_REMOTE_DISCONNECT; goto exit; @@ -4044,7 +4055,7 @@ AsyncTCPSocketWriteBuffers(AsyncTCPSocket *s) // IN } if (AsyncTCPSocketGetState(s) != AsyncSocketConnected) { - TCPSOCKWARN(s, "write buffers on a disconnected socket!\n"); + TCPSOCKWARN(s, "write buffers on a disconnected or rdonly socket!\n"); return ASOCKERR_GENERIC; } @@ -4360,7 +4371,8 @@ AsyncTCPSocketWaitForConnection(AsyncSocket *base, // IN: ASSERT(AsyncTCPSocketIsLocked(s)); - if (AsyncTCPSocketGetState(s) == AsyncSocketConnected) { + if (AsyncTCPSocketGetState(s) == AsyncSocketConnected || + AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly) { return ASOCKERR_SUCCESS; } @@ -4499,7 +4511,8 @@ AsyncTCPSocketDoOneMsg(AsyncSocket *base, // IN int retVal; ASSERT(AsyncTCPSocketIsLocked(s)); - ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || + (AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly && read)); if (read) { if (s->inRecvLoop) { @@ -4546,7 +4559,8 @@ AsyncTCPSocketDoOneMsg(AsyncSocket *base, // IN if (AsyncTCPSocketGetState(s) != AsyncSocketClosed && s->recvCb) { ASSERT(s->base.refCount > 1); /* We shouldn't be last user of socket. */ - ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || + AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); /* * If AsyncTCPSocketPoll or AsyncTCPSocketFillRecvBuffer fails, do not * add the recv callback as it may never fire. @@ -4620,7 +4634,8 @@ AsyncSocket_TCPDrainRecv(AsyncSocket *base, // IN VmTimeType startMS = Hostinfo_SystemTimerMS(); VmTimeType nowMS; - ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || + AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); ASSERT(s->recvCb); /* We are supposed to call someone... */ if (!AsyncTCPSocketIsLocked(s) || !Poll_LockingEnabled()) { @@ -4664,7 +4679,8 @@ AsyncSocket_TCPDrainRecv(AsyncSocket *base, // IN TCPSOCKWARN(s, "%s: failed to poll on the socket during read.\n", __FUNCTION__); } - } else if (AsyncTCPSocketGetState(s) == AsyncSocketConnected) { + } else if (AsyncTCPSocketGetState(s) == AsyncSocketConnected || + AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly) { ASSERT(asock == s); retVal = AsyncTCPSocketFillRecvBuffer(s); } @@ -4689,7 +4705,8 @@ retry: } timeoutMS -= nowMS - startMS; startMS = nowMS; - ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected && s->recvCb); + ASSERT((AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly || + AsyncTCPSocketGetState(s) == AsyncSocketConnected) && s->recvCb); } if (cbRemoved) { @@ -4699,7 +4716,8 @@ retry: * add the recv callback as it may never fire. */ if (retVal == ASOCKERR_TIMEOUT) { - ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected || + AsyncTCPSocketGetState(s) == AsyncSocketConnectedRdOnly); ASSERT(s->base.refCount > 1); /* We better not be the last user */ retVal = AsyncTCPSocketRegisterRecvCb(s); Log("SOCKET reregister recvCb after DrainRecv (ref %d)\n", @@ -4754,7 +4772,7 @@ AsyncTCPSocketFlush(AsyncSocket *base, // IN AsyncTCPSocketAddRef(s); if (AsyncTCPSocketGetState(s) != AsyncSocketConnected) { - TCPSOCKWARN(s, "flush called but state is not connected!\n"); + TCPSOCKWARN(s, "flush called but state is rdonly or disconnected!\n"); retVal = ASOCKERR_INVAL; goto outHaveLock; } @@ -4886,6 +4904,12 @@ AsyncTCPSocketCancelRecvCb(AsyncTCPSocket *asock) // IN: { ASSERT(AsyncTCPSocketIsLocked(asock)); + /* + * We could fire the current recv completion callback here, but in + * practice clients won't want to know about partial reads since it just + * complicates the common case (i.e. every read callback would need to + * check the len parameter). + */ if (asock->recvCbTimer) { AsyncTCPSocketPollRemove(asock, FALSE, 0, asock->internalRecvFn); asock->recvCbTimer = FALSE; @@ -4911,6 +4935,91 @@ AsyncTCPSocketCancelRecvCb(AsyncTCPSocket *asock) // IN: } +/* + *---------------------------------------------------------------------------- + * + * AsyncTCPSocketCancelSendCb -- + * + * Socket specific code for canceling callbacks when a send + * request is being canceled. + * + * This function assumes the caller has done AsyncTCPSocketAddRef, + * since the sendFn callback registered might close the socket. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +AsyncTCPSocketCancelSendCb(AsyncTCPSocket *asock) // IN: +{ + if (asock->sendCb) { + Bool removed; + + TCPSOCKLOG(1, asock, + "sendBufList is non-NULL, removing send callback\n"); + + /* + * The send callback could be either a device or RTime callback, so + * we check the latter if it wasn't the former. + */ + + if (asock->sendCbTimer) { + removed = AsyncTCPSocketPollRemove(asock, FALSE, 0, + asock->internalSendFn); + } else { + removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, + asock->internalSendFn); + } + ASSERT(removed || AsyncTCPSocketPollParams(asock)->iPoll); + asock->sendCb = FALSE; + asock->sendCbTimer = FALSE; + } + + /* + * Go through any send buffers on the list and fire their + * callbacks, reflecting back how much of each buffer has been + * submitted to the kernel. For the first buffer in the list that + * may be non-zero, for subsequent buffers it will be zero. + * + * Unlike AsyncTCPSocketCancelRecvCb, the argument of firing callbacks + * here is that the common case for writes is "fire and forget", e.g. + * send this buffer and free it. Firing the triggers at close time + * simplifies client code, since the clients aren't forced to keep track + * of send buffers themselves. Clients can figure out how much data was + * actually transmitted (if they care) by checking the len parameter + * passed to the send callback. + * + * A modification suggested by Jeremy is to pass a list of unsent + * buffers and their completion callbacks to the error handler if one is + * registered, and only fire the callbacks here if there was no error + * handler invoked. + */ + + while (asock->sendBufList) { + /* + * Pop each remaining buffer and fire its completion callback. + */ + + SendBufList *cur = asock->sendBufList; + int pos = asock->sendPos; + + asock->sendBufList = asock->sendBufList->next; + asock->sendPos = 0; + + if (cur->sendFn) { + cur->sendFn(cur->buf, pos, BaseSocket(asock), cur->clientData); + } + free(cur); + } +} + + /* *---------------------------------------------------------------------------- * @@ -4945,32 +5054,12 @@ AsyncTCPSocketCancelCbForClose(AsyncSocket *base) // IN: Bool removed; ASSERT(AsyncTCPSocketIsLocked(asock)); - - if (AsyncTCPSocketGetState(asock) == AsyncSocketConnected) { + if (AsyncTCPSocketGetState(asock) == AsyncSocketConnected || + AsyncTCPSocketGetState(asock) == AsyncSocketConnectedRdOnly) { AsyncTCPSocketSetState(asock, AsyncSocketCBCancelled); } - /* - * Remove the read and write poll callbacks. - * - * We could fire the current recv completion callback here, but in - * practice clients won't want to know about partial reads since it just - * complicates the common case (i.e. every read callback would need to - * check the len parameter). - * - * For writes, however, we *do* fire all of the callbacks. The argument - * here is that the common case for writes is "fire and forget", e.g. - * send this buffer and free it. Firing the triggers at close time - * simplifies client code, since the clients aren't forced to keep track - * of send buffers themselves. Clients can figure out how much data was - * actually transmitted (if they care) by checking the len parameter - * passed to the send callback. - * - * A modification suggested by Jeremy is to pass a list of unsent - * buffers and their completion callbacks to the error handler if one is - * registered, and only fire the callbacks here if there was no error - * handler invoked. - */ + /* Remove the read callback. Similar to AsyncTCPSocketCancelRecvCb */ ASSERT(!asock->base.recvBuf || asock->base.recvFn); @@ -4992,50 +5081,10 @@ AsyncTCPSocketCancelCbForClose(AsyncSocket *base) // IN: asock->base.recvBuf = NULL; } - if (asock->sendCb) { - TCPSOCKLOG(1, asock, - "sendBufList is non-NULL, removing send callback\n"); + /* Remove the write callback. */ - /* - * The send callback could be either a device or RTime callback, so - * we check the latter if it wasn't the former. - */ - - if (asock->sendCbTimer) { - removed = AsyncTCPSocketPollRemove(asock, FALSE, 0, - asock->internalSendFn); - } else { - removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, - asock->internalSendFn); - } - ASSERT(removed || AsyncTCPSocketPollParams(asock)->iPoll); - asock->sendCb = FALSE; - asock->sendCbTimer = FALSE; - } - - /* - * Go through any send buffers on the list and fire their - * callbacks, reflecting back how much of each buffer has been - * submitted to the kernel. For the first buffer in the list that - * may be non-zero, for subsequent buffers it will be zero. - */ AsyncTCPSocketAddRef(asock); - while (asock->sendBufList) { - /* - * Pop each remaining buffer and fire its completion callback. - */ - - SendBufList *cur = asock->sendBufList; - int pos = asock->sendPos; - - asock->sendBufList = asock->sendBufList->next; - asock->sendPos = 0; - - if (cur->sendFn) { - cur->sendFn(cur->buf, pos, BaseSocket(asock), cur->clientData); - } - free(cur); - } + AsyncTCPSocketCancelSendCb(asock); AsyncTCPSocketRelease(asock); return ASOCKERR_SUCCESS; } @@ -5105,6 +5154,74 @@ AsyncTCPSocketSetCloseOptions(AsyncSocket *base, // IN } +/* + *---------------------------------------------------------------------------- + * + * AsyncTCPSocketCloseWrite -- + * + * Close the write side of AsyncTCPSocket. + * + * Results: + * ASOCKERR_*. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +AsyncTCPSocketCloseWrite(AsyncSocket *base) // IN: +{ +#ifdef VMX86_TOOLS + /* For tools, don't support closeWrite for now */ + return ASOCKERR_INVAL; +#else + AsyncTCPSocket *asock = TCPSocket(base); + int ret; + + ASSERT(AsyncTCPSocketIsLocked(asock)); + + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { + return ASOCKERR_INVAL; + } + if (SSL_IsEncrypted(asock->sslSock)) { + /* SSL doesn't support half-close */ + return ASOCKERR_INVAL; + } + ASSERT(asock->listenAsock4 == NULL); + ASSERT(asock->listenAsock6 == NULL); + + if (asock->flushEnabledMaxWaitMsec && !asock->base.errorSeen) { + int ret = AsyncTCPSocketFlush(BaseSocket(asock), + asock->flushEnabledMaxWaitMsec); + if (ret != ASOCKERR_SUCCESS) { + TCPSOCKWARN(asock, + "AsyncTCPSocket_Flush failed: %s. (ignored).\n", + AsyncSocket_Err2String(ret)); + } + } + AsyncTCPSocketSetState(asock, AsyncSocketConnectedRdOnly); + AsyncTCPSocketAddRef(asock); + AsyncTCPSocketCancelSendCb(asock); + + ret = SSLGeneric_shutdown(SSL_GetFd(asock->sslSock)); + if (ret < 0) { + asock->genericErrno = ASOCK_LASTERROR(); + TCPSOCKWARN(asock, "shutdown error %d: %s\n", asock->genericErrno, + Err_Errno2String(asock->genericErrno)); + ret = ASOCKERR_GENERIC; + goto out; + } + ret = ASOCKERR_SUCCESS; + +out: + AsyncTCPSocketRelease(asock); + return ret; +#endif +} + + /* *---------------------------------------------------------------------------- * @@ -5153,8 +5270,7 @@ AsyncTCPSocketClose(AsyncSocket *base) // IN if (asock->flushEnabledMaxWaitMsec && AsyncTCPSocketGetState(asock) == AsyncSocketConnected && !asock->base.errorSeen) { - int ret = AsyncTCPSocketFlush(BaseSocket(asock), - asock->flushEnabledMaxWaitMsec); + int ret = AsyncTCPSocketFlush(base, asock->flushEnabledMaxWaitMsec); if (ret != ASOCKERR_SUCCESS) { TCPSOCKWARN(asock, "AsyncTCPSocket_Flush failed: %s. Closing now.\n", @@ -5189,7 +5305,8 @@ AsyncTCPSocketClose(AsyncSocket *base) // IN break; case AsyncSocketConnected: - TCPSOCKLOG(1, asock, "old state was connected\n"); + case AsyncSocketConnectedRdOnly: + TCPSOCKLOG(1, asock, "old state was connected/rdonly\n"); AsyncTCPSocketCancelCbForClose(BaseSocket(asock)); break; @@ -5940,7 +6057,8 @@ AsyncTCPSocketCancelRecv(AsyncSocket *base, // IN ASSERT(AsyncTCPSocketIsLocked(asock)); - if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && + AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) { Warning(ASOCKPREFIX "Failed to cancel request on disconnected socket!\n"); return ASOCKERR_INVAL; } @@ -5994,7 +6112,8 @@ AsyncTCPSocketGetReceivedFd(AsyncSocket *base) // IN ASSERT(AsyncTCPSocketIsLocked(asock)); - if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected && + AsyncTCPSocketGetState(asock) != AsyncSocketConnectedRdOnly) { Warning(ASOCKPREFIX "Failed to receive fd on disconnected socket!\n"); return -1; } @@ -6389,13 +6508,20 @@ AsyncTCPSocketSetOption(AsyncSocket *asyncSocket, // IN/OUT * Handle non-native options first. */ - if ((layer == ASYNC_SOCKET_OPTS_LAYER_BASE) && - (optID == ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE)) { - ASSERT(inBufLen == sizeof(Bool)); - tcpSocket->sendLowLatency = *((const Bool *)valuePtr); - TCPSOCKLG0(tcpSocket, "%s: sendLowLatencyMode set to [%d].\n", - __FUNCTION__, (int)tcpSocket->sendLowLatency); - return ASOCKERR_SUCCESS; + if (layer == ASYNC_SOCKET_OPTS_LAYER_BASE) { + switch (optID) { + case ASYNC_SOCKET_OPT_SEND_LOW_LATENCY_MODE: + ASSERT(inBufLen == sizeof(Bool)); + tcpSocket->sendLowLatency = *((const Bool *)valuePtr); + TCPSOCKLG0(tcpSocket, "%s: sendLowLatencyMode set to [%d].\n", + __FUNCTION__, (int)tcpSocket->sendLowLatency); + return ASOCKERR_SUCCESS; + default: + TCPSOCKLG0(tcpSocket, "%s: could not set non-native option [%d]" + " for TCP socket -- option not supported.\n", + __FUNCTION__, (int)optID); + return ASOCKERR_INVAL; + } } /* diff --git a/open-vm-tools/lib/include/asyncsocket.h b/open-vm-tools/lib/include/asyncsocket.h index dad848093..c2852d159 100644 --- a/open-vm-tools/lib/include/asyncsocket.h +++ b/open-vm-tools/lib/include/asyncsocket.h @@ -194,6 +194,7 @@ typedef enum AsyncSocketState { AsyncSocketConnected, AsyncSocketCBCancelled, AsyncSocketClosed, + AsyncSocketConnectedRdOnly, } AsyncSocketState; @@ -747,6 +748,11 @@ int AsyncSocket_SetCloseOptions(AsyncSocket *asock, int flushEnabledMaxWaitMsec, AsyncSocketCloseFn closeCb); +/* + * Close the write side of the connection. + */ +int AsyncSocket_CloseWrite(AsyncSocket *asock); + /* * Close the connection and destroy the asock. */