From: Oliver Kurth Date: Fri, 15 Sep 2017 18:23:06 +0000 (-0700) Subject: Reorganization of the AsyncSocket API layer into an interface dispatch X-Git-Tag: stable-10.2.0~508 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8d9d99705dd43679a5da913131345c8bd470a8a9;p=thirdparty%2Fopen-vm-tools.git Reorganization of the AsyncSocket API layer into an interface dispatch layer and separate disjoint socket implementations. Common header file change; not applicable to open-vm-tools. --- diff --git a/open-vm-tools/lib/asyncsocket/Makefile.am b/open-vm-tools/lib/asyncsocket/Makefile.am index 48a484496..6ab62fd03 100644 --- a/open-vm-tools/lib/asyncsocket/Makefile.am +++ b/open-vm-tools/lib/asyncsocket/Makefile.am @@ -19,6 +19,7 @@ noinst_LTLIBRARIES = libAsyncSocket.la libAsyncSocket_la_SOURCES = libAsyncSocket_la_SOURCES += asyncsocket.c +libAsyncSocket_la_SOURCES += asyncSocketBase.c libAsyncSocket_la_SOURCES += asyncSocketInterface.c AM_CFLAGS = diff --git a/open-vm-tools/lib/asyncsocket/asyncSocketBase.c b/open-vm-tools/lib/asyncsocket/asyncSocketBase.c new file mode 100644 index 000000000..d91deceb7 --- /dev/null +++ b/open-vm-tools/lib/asyncsocket/asyncSocketBase.c @@ -0,0 +1,767 @@ +/********************************************************* + * Copyright (C) 2016 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. + * + *********************************************************/ + +/********************************************************* + * The contents of this file are subject to the terms of the Common + * Development and Distribution License (the "License") version 1.0 + * and no later version. You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at + * http://www.opensource.org/licenses/cddl1.php + * + * See the License for the specific language governing permissions + * and limitations under the License. + * + *********************************************************/ + +/* + * asyncSocketBase.c -- + * + * This exposes the public functions of the AsyncSocket library. + * This file itself just contains stubs which call the function + * pointers in the socket's virtual table. + * + */ + +#include "vmware.h" +#include "asyncsocket.h" +#include "asyncSocketBase.h" +#include "msg.h" +#include "log.h" + +#define LOGLEVEL_MODULE asyncsocket +#include "loglevel_user.h" + + +/* + *----------------------------------------------------------------------------- + * + * AsyncSocketInternalIncRef -- + * + * Increments reference count on AsyncSocket struct and optionally + * takes the lock. This function is used to implement both Lock + * and AddRef. + * + * Results: + * New reference count. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +AsyncSocketInternalIncRef(AsyncSocket *asock, // IN + Bool lock) // IN +{ + if (lock && asock->pollParams.lock) { + MXUser_AcquireRecLock(asock->pollParams.lock); + } + ASSERT(asock->refCount > 0); + ++asock->refCount; +} + + +/* + *----------------------------------------------------------------------------- + * + * AsyncSocketInternalDecRef -- + * + * Decrements reference count on AsyncSocket struct, freeing it when it + * reaches 0. If "unlock" is TRUE, releases the lock after decrementing + * the count. + * + * This function is used to implement both Unlock and DecRef. + * + * Results: + * None. + * + * Side effects: + * May free struct. + * + *----------------------------------------------------------------------------- + */ + +static INLINE void +AsyncSocketInternalDecRef(AsyncSocket *s, // IN + Bool unlock) // IN +{ + int count = --s->refCount; + + if (unlock && s->pollParams.lock) { + MXUser_ReleaseRecLock(s->pollParams.lock); + } + + ASSERT(count >= 0); + if (UNLIKELY(count == 0)) { + ASOCKLOG(1, s, ("Final release; freeing asock struct\n")); + VT(s)->destroy(s); + } else { + ASOCKLOG(1, s, ("Release (count now %d)\n", count)); + } +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocketLock -- + * AsyncSocketUnlock -- + * + * Acquire/Release the lock provided by the client when creating the + * AsyncSocket object. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +void +AsyncSocketLock(AsyncSocket *asock) // IN: +{ + AsyncSocketInternalIncRef(asock, TRUE); +} + +void +AsyncSocketUnlock(AsyncSocket *asock) // IN: +{ + AsyncSocketInternalDecRef(asock, TRUE); +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocketIsLocked -- + * + * If a lock is associated with the socket, check whether the calling + * thread holds the lock. + * + * Results: + * TRUE if calling thread holds the lock, or if there is no assoicated + * lock. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +Bool +AsyncSocketIsLocked(AsyncSocket *asock) // IN: +{ + if (asock->pollParams.lock && Poll_LockingEnabled()) { + return MXUser_IsCurThreadHoldingRecLock(asock->pollParams.lock); + } + return TRUE; +} + + +/* + *----------------------------------------------------------------------------- + * + * AsyncSocketAddRef -- + * + * Increments reference count on AsyncSocket struct. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +void +AsyncSocketAddRef(AsyncSocket *s) // IN +{ + AsyncSocketInternalIncRef(s, FALSE); +} + + +/* + *----------------------------------------------------------------------------- + * + * AsyncSocketRelease -- + * + * Decrements reference count on AsyncSocket struct, freeing it when it + * reaches 0. If "unlock" is TRUE, releases the lock after decrementing + * the count. + * + * Results: + * None. + * + * Side effects: + * May free struct. + * + *----------------------------------------------------------------------------- + */ + +void +AsyncSocketRelease(AsyncSocket *s) // IN: +{ + AsyncSocketInternalDecRef(s, FALSE); +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocketGetState -- + * + * Accessor function for the state in the base class. + * + *---------------------------------------------------------------------------- + */ + +AsyncSocketState +AsyncSocketGetState(AsyncSocket *asock) // IN +{ + ASSERT(AsyncSocketIsLocked(asock)); + return asock->state; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocketSetState -- + * + * Modifier function for the state in the base class. + * + *---------------------------------------------------------------------------- + */ + +void +AsyncSocketSetState(AsyncSocket *asock, // IN/OUT + AsyncSocketState state) // IN +{ + asock->state = state; +} + + +/* + *----------------------------------------------------------------------------- + * + * AsyncSocketGetPollParams -- + * + * Accessor function for the pollParams struct in the base socket. + * + *----------------------------------------------------------------------------- + */ + +AsyncSocketPollParams * +AsyncSocketGetPollParams(AsyncSocket *s) // IN +{ + return &s->pollParams; +} + + +/* + *----------------------------------------------------------------------------- + * + * AsyncSocketInitSocket -- + * + * Initialize the AsyncSocket base struct. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +void +AsyncSocketInitSocket(AsyncSocket *s, // IN/OUT + AsyncSocketPollParams *pollParams, // IN + const AsyncSocketVTable *vtable) // IN +{ + /* + * The sockets each have a "unique" ID, which is just an + * incrementing integer. + */ + static Atomic_uint32 nextid = { 1 }; + + s->id = Atomic_ReadInc32(&nextid); + s->refCount = 1; + s->vt = vtable; + if (pollParams) { + s->pollParams = *pollParams; + } else { + s->pollParams.pollClass = POLL_CS_MAIN; + s->pollParams.flags = 0; + s->pollParams.lock = NULL; + s->pollParams.iPoll = NULL; + } +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_Init -- + * + * Initialize the various socket subsytems. Currently just TCP, this + * will expand. + * + * Results: + * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. + * + * Side effects: + * See subsystems. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_Init(void) +{ + return AsyncTCPSocket_Init(); +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_GetID -- + * + * Returns a unique identifier for the asock. + * + * Results: + * Integer id or ASOCKERR_INVAL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_GetID(AsyncSocket *asock) // IN +{ + if (!asock) { + return ASOCKERR_INVAL; /* For some reason we return ID 5 + for null pointers! */ + } else { + return asock->id; + } +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_SetErrorFn -- + * + * Sets the error handling function for the asock. The error function + * is invoked automatically on I/O errors. + * + * Results: + * ASOCKERR_SUCCESS or ASOCKERR_INVAL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_SetErrorFn(AsyncSocket *asock, // IN/OUT + AsyncSocketErrorFn errorFn, // IN + void *clientData) // IN +{ + if (!asock) { + return ASOCKERR_INVAL; + } else { + AsyncSocketLock(asock); + asock->errorFn = errorFn; + asock->errorClientData = clientData; + AsyncSocketUnlock(asock); + return ASOCKERR_SUCCESS; + } +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocketHandleError -- + * + * Internal error handling helper. Changes the socket's state to error, + * and calls the registered error handler or closes the socket. + * + * Results: + * None. + * + * Side effects: + * Lots. + * + *---------------------------------------------------------------------------- + */ + +void +AsyncSocketHandleError(AsyncSocket *asock, // IN + int asockErr) // IN +{ + ASSERT(asock); + asock->errorSeen = TRUE; + if (asock->errorFn) { + ASOCKLOG(3, asock, ("firing error callback (%s)\n", + AsyncSocket_Err2String(asockErr))); + asock->errorFn(asockErr, asock, asock->errorClientData); + } else { + ASOCKLOG(3, asock, ("no error callback, closing socket (%s)\n", + AsyncSocket_Err2String(asockErr))); + AsyncSocket_Close(asock); + } +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocketCheckAndDispatchRecv -- + * + * Check if the recv buffer is full and dispatch the client callback. + * + * Handles the possibility that the client registers a new receive buffer + * or closes the socket in their callback. + * + * Results: + * TRUE if the socket was closed or the receive was cancelled, + * FALSE if the caller should continue to try to receive data. + * + * Side effects: + * Could fire recv completion or trigger socket destruction. + * + *---------------------------------------------------------------------------- + */ + +Bool +AsyncSocketCheckAndDispatchRecv(AsyncSocket *s, // IN + int *result) // OUT +{ + ASSERT(s); + ASSERT(result); + ASSERT(s->recvFn); + ASSERT(s->recvBuf); + ASSERT(s->recvLen > 0); + ASSERT(s->recvPos > 0); + ASSERT(s->recvPos <= s->recvLen); + + /* + * The application may close the socket in this callback. This + * asserts that even if that happens, the socket will not be + * immediately freed in the middle of our function. + */ + ASSERT(s->refCount > 1); + + if (s->recvPos == s->recvLen || s->recvFireOnPartial) { + void *recvBuf = s->recvBuf; + ASOCKLOG(3, s, ("recv buffer full, calling recvFn\n")); + + /* + * We do this dance in case the handler frees the buffer (so + * that there's no possible window where there are dangling + * references here. Obviously if the handler frees the buffer, + * but them fails to register a new one, we'll put back the + * dangling reference in the automatic reset case below, but + * there's currently a limit to how far we go to shield clients + * who use our API in a broken way. + */ + + s->recvBuf = NULL; + s->recvFn(recvBuf, s->recvPos, s, s->recvClientData); + if (s->state == AsyncSocketClosed) { + ASOCKLG0(s, ("owner closed connection in recv callback\n")); + *result = ASOCKERR_CLOSED; + return TRUE; + } else if (s->recvFn == NULL && s->recvLen == 0) { + /* + * Further recv is cancelled from within the last recvFn, see + * AsyncSocket_CancelRecv(). So exit from the loop. + */ + *result = ASOCKERR_SUCCESS; + return TRUE; + } else if (s->recvPos > 0) { + /* + * Automatically reset keeping the current handler. Checking + * that recvPos is still non-zero implies that the + * application has not called AsyncSocket_Recv or + * _RecvPartial in the callback. + */ + s->recvPos = 0; + s->recvBuf = recvBuf; + *result = ASOCKERR_SUCCESS; + return FALSE; + } else { + *result = ASOCKERR_SUCCESS; + return FALSE; + } + } else { + *result = ASOCKERR_SUCCESS; + return FALSE; + } +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocketSetRecvBuf -- + * + * Helper function to validate socket state and recvBuf + * parameters before setting the recvBuf values in the base + * class. + * + * Results: + * ASOCKERR_SUCCESS or ASOCKERR_*. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocketSetRecvBuf(AsyncSocket *asock, // IN: + void *buf, // IN: + int len, // IN: + Bool fireOnPartial, // IN: + void *cb, // IN: + void *cbData) // IN: +{ + ASSERT(AsyncSocketIsLocked(asock)); + + if (!asock->errorFn) { + ASOCKWARN(asock, ("%s: no registered error handler!\n", __FUNCTION__)); + return ASOCKERR_INVAL; + } + + if (!buf || !cb || len <= 0) { + ASOCKWARN(asock, ("Recv called with invalid arguments!\n")); + return ASOCKERR_INVAL; + } + + if (AsyncSocketGetState(asock) != AsyncSocketConnected) { + ASOCKWARN(asock, ("recv called but state is not connected!\n")); + return ASOCKERR_NOTCONNECTED; + } + + if (asock->recvBuf && asock->recvPos != 0) { + ASOCKWARN(asock, ("Recv called -- partially read buffer discarded.\n")); + } + + asock->recvBuf = buf; + asock->recvLen = len; + asock->recvFireOnPartial = fireOnPartial; + asock->recvFn = cb; + asock->recvClientData = cbData; + asock->recvPos = 0; + + return ASOCKERR_SUCCESS; +} + + +/* + *----------------------------------------------------------------------------- + * + * WebSocketCancelRecv -- + * + * Call this function if you know what you are doing. This should + * be called if you want to synchronously receive the outstanding + * data on the socket. It returns number of partially read bytes + * (if any). A partially read response may exist as + * AsyncSocketRecvCallback calls the recv callback only when all + * the data has been received. + * + * Results: + * None + * + * Side effects: + * Subsequent client call to AsyncSocket_Recv can reinstate async behaviour. + * + *----------------------------------------------------------------------------- + */ + +void +AsyncSocketCancelRecv(AsyncSocket *asock, // IN + int *partialRecvd, // OUT + void **recvBuf, // OUT + void **recvFn) // IN +{ + if (partialRecvd) { + *partialRecvd = asock->recvPos; + } + if (recvFn) { + *recvFn = asock->recvFn; + } + if (recvBuf) { + *recvBuf = asock->recvBuf; + } + + asock->recvBuf = NULL; + asock->recvFn = NULL; + asock->recvPos = 0; + asock->recvLen = 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_Err2String -- + * + * Returns the error string associated with error code. + * + * Results: + * Error string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +const char * +AsyncSocket_Err2String(int err) // IN +{ + return Msg_StripMSGID(AsyncSocket_MsgError(err)); +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_MsgError -- + * + * Returns the message associated with error code. + * + * Results: + * Message string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +const char * +AsyncSocket_MsgError(int asyncSockError) // IN +{ + const char *result = NULL; + switch (asyncSockError) { + case ASOCKERR_SUCCESS: + result = MSGID(asyncsocket.success) "Success"; + break; + case ASOCKERR_GENERIC: + result = MSGID(asyncsocket.generic) "Asyncsocket error"; + break; + case ASOCKERR_INVAL: + result = MSGID(asyncsocket.invalid) "Invalid parameters"; + break; + case ASOCKERR_TIMEOUT: + result = MSGID(asyncsocket.timeout) "Time-out error"; + break; + case ASOCKERR_NOTCONNECTED: + result = MSGID(asyncsocket.notconnected) "Local socket not connected"; + break; + case ASOCKERR_REMOTE_DISCONNECT: + result = MSGID(asyncsocket.remotedisconnect) "Remote disconnected"; + break; + case ASOCKERR_CLOSED: + result = MSGID(asyncsocket.closed) "Closed socket"; + break; + case ASOCKERR_CONNECT: + result = MSGID(asyncsocket.connect) "Connection error"; + break; + case ASOCKERR_POLL: + result = MSGID(asyncsocket.poll) "Poll registration error"; + break; + case ASOCKERR_BIND: + result = MSGID(asyncsocket.bind) "Socket bind error"; + break; + case ASOCKERR_BINDADDRINUSE: + result = MSGID(asyncsocket.bindaddrinuse) "Socket bind address already in use"; + break; + case ASOCKERR_LISTEN: + result = MSGID(asyncsocket.listen) "Socket listen error"; + break; + case ASOCKERR_CONNECTSSL: + result = MSGID(asyncsocket.connectssl) "Connection error: could not negotiate SSL"; + break; + case ASOCKERR_NETUNREACH: + result = MSGID(asyncsocket.netunreach) "Network unreachable"; + break; + case ASOCKERR_ADDRUNRESV: + result = MSGID(asyncsocket.addrunresv) "Address unresolvable"; + break; + } + + if (!result) { + Warning("%s was passed bad code %d\n", __FUNCTION__, asyncSockError); + result = MSGID(asyncsocket.unknown) "Unknown error"; + } + return result; +} + + +/** + *----------------------------------------------------------------------------- + * + * stristr -- + * + * Do you know strstr from ? + * So this one is the same, but without the case sensitivity. + * + * Results: + * return a pointer to the first occurrence of needle in haystack, + * or NULL if needle does not appear in haystack. If needle is zero + * length, the function returns haystack. + * + * Side effects: + * none + * + *----------------------------------------------------------------------------- + */ + +const char * +stristr(const char *haystack, // IN + const char *needle) // IN +{ + if (*needle) { + int len = strlen(needle); + for (; *haystack; haystack++) { + if (strncasecmp(haystack, needle, len) == 0) { + return haystack; + } + } + return NULL; + } else { + return haystack; + } +} diff --git a/open-vm-tools/lib/asyncsocket/asyncSocketBase.h b/open-vm-tools/lib/asyncsocket/asyncSocketBase.h new file mode 100644 index 000000000..13126fe40 --- /dev/null +++ b/open-vm-tools/lib/asyncsocket/asyncSocketBase.h @@ -0,0 +1,89 @@ +/********************************************************* + * Copyright (C) 2011,2014-2016 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. + * + *********************************************************/ + +/********************************************************* + * The contents of this file are subject to the terms of the Common + * Development and Distribution License (the "License") version 1.0 + * and no later version. You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at + * http://www.opensource.org/licenses/cddl1.php + * + * See the License for the specific language governing permissions + * and limitations under the License. + * + *********************************************************/ + +#ifndef __ASYNC_SOCKET_BASE_H__ +#define __ASYNC_SOCKET_BASE_H__ + +#ifdef USE_SSL_DIRECT +#include "sslDirect.h" +#else +#include "ssl.h" +#endif + +#include "asyncSocketVTable.h" + +/* + * The abstract base class for all asyncsocket implementations. + */ +struct AsyncSocket { + uint32 id; + uint32 refCount; + AsyncSocketPollParams pollParams; + AsyncSocketState state; + + Bool errorSeen; + AsyncSocketErrorFn errorFn; + void *errorClientData; + + void *recvBuf; + int recvPos; + int recvLen; + AsyncSocketRecvFn recvFn; + void *recvClientData; + Bool recvFireOnPartial; + + const AsyncSocketVTable *vt; +}; + +void AsyncSocketInitSocket(AsyncSocket *asock, + AsyncSocketPollParams *params, + const AsyncSocketVTable *vtable); + +void AsyncSocketLock(AsyncSocket *asock); +void AsyncSocketUnlock(AsyncSocket *asock); +Bool AsyncSocketIsLocked(AsyncSocket *asock); +void AsyncSocketAddRef(AsyncSocket *asock); +void AsyncSocketRelease(AsyncSocket *s); +AsyncSocketState AsyncSocketGetState(AsyncSocket *sock); +void AsyncSocketSetState(AsyncSocket *sock, AsyncSocketState state); +int AsyncSocketSetRecvBuf(AsyncSocket *asock, void *buf, int len, + Bool fireOnPartial, void *cb, void *cbData); +Bool AsyncSocketCheckAndDispatchRecv(AsyncSocket *s, int *result); +AsyncSocketPollParams *AsyncSocketGetPollParams(AsyncSocket *s); +void AsyncSocketHandleError(AsyncSocket *asock, int asockErr); +void AsyncSocketCancelRecv(AsyncSocket *asock, int *partialRecvd, + void **recvBuf, void **recvFn); + + +int AsyncTCPSocket_Init(void); + +#endif diff --git a/open-vm-tools/lib/asyncsocket/asyncSocketInt.h b/open-vm-tools/lib/asyncsocket/asyncSocketInt.h deleted file mode 100644 index 5ccca16d1..000000000 --- a/open-vm-tools/lib/asyncsocket/asyncSocketInt.h +++ /dev/null @@ -1,573 +0,0 @@ -/********************************************************* - * Copyright (C) 2011,2014-2016 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. - * - *********************************************************/ - -/********************************************************* - * The contents of this file are subject to the terms of the Common - * Development and Distribution License (the "License") version 1.0 - * and no later version. You may not use this file except in - * compliance with the License. - * - * You can obtain a copy of the License at - * http://www.opensource.org/licenses/cddl1.php - * - * See the License for the specific language governing permissions - * and limitations under the License. - * - *********************************************************/ - -#ifndef __ASYNC_SOCKET_INT_H__ -#define __ASYNC_SOCKET_INT_H__ - -/* - * asyncsocket.h -- - * - * The AsyncSocket object is a fairly simple wrapper around a basic TCP - * socket. It's potentially asynchronous for both read and write - * operations. Reads are "requested" by registering a receive function - * that is called once the requested amount of data has been read from - * the socket. Similarly, writes are queued along with a send function - * that is called once the data has been written. Errors are reported via - * a separate callback. - */ - -#define INCLUDE_ALLOW_VMCORE -#define INCLUDE_ALLOW_USERLEVEL -#include "includeCheck.h" - -#ifdef _WIN32 -/* - * We redefine strcpy/strcat because the Windows SDK uses it for getaddrinfo(). - * When we upgrade SDKs, this redefinition can go away. - * Note: Now we are checking if we have secure libs for string operations - */ -#if !(defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L) -#define strcpy(dst,src) Str_Strcpy((dst), (src), 0x7FFFFFFF) -#define strcat(dst,src) Str_Strcat((dst), (src), 0x7FFFFFFF) -#endif -#include -#include -#include -#include -#include -#if !(defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L) -#undef strcpy -#undef strcat -#endif -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#include "vmware.h" -#include "random.h" - -#ifdef USE_SSL_DIRECT -#include "sslDirect.h" -#else -#include "ssl.h" -#endif - -#ifdef _WIN32 -#define ASOCK_LASTERROR() WSAGetLastError() -#define ASOCK_ENOTCONN WSAENOTCONN -#define ASOCK_ENOTSOCK WSAENOTSOCK -#define ASOCK_EADDRINUSE WSAEADDRINUSE -#define ASOCK_ECONNECTING WSAEWOULDBLOCK -#define ASOCK_EWOULDBLOCK WSAEWOULDBLOCK -#define ASOCK_ENETUNREACH WSAENETUNREACH -#else -#define ASOCK_LASTERROR() errno -#define ASOCK_ENOTCONN ENOTCONN -#define ASOCK_ENOTSOCK ENOTSOCK -#define ASOCK_EADDRINUSE EADDRINUSE -#define ASOCK_ECONNECTING EINPROGRESS -#define ASOCK_EWOULDBLOCK EWOULDBLOCK -#define ASOCK_ENETUNREACH ENETUNREACH -#endif - -#define WEBSOCKET_HTTP_BUFFER_SIZE 8192 - -typedef struct WebSocketHttpRequest { - char buf[WEBSOCKET_HTTP_BUFFER_SIZE + 1]; /* used for request & response */ - int32 bufLen; - Bool overflow; -} WebSocketHttpRequest; - -typedef enum { - WEB_SOCKET_FRAME_OPCODE_BINARY = 0x02, - WEB_SOCKET_FRAME_OPCODE_CLOSE = 0x08, -} WebSocketFrameOpcode; - -typedef enum { - WEB_SOCKET_STATE_CONNECTING = 0, - WEB_SOCKET_STATE_OPEN = 1, - WEB_SOCKET_STATE_CLOSING = 2, - WEB_SOCKET_STATE_CLOSED = 3, -} WebSocketState; - -typedef enum { - WEB_SOCKET_NEED_FRAME_TYPE = 0, - WEB_SOCKET_NEED_FRAME_SIZE = 1, - WEB_SOCKET_NEED_EXTENDED_FRAME_SIZE = 2, - WEB_SOCKET_NEED_FRAME_MASK = 3, - WEB_SOCKET_NEED_FRAME_DATA = 4, -} WebSocketDecodeState; - -/* - * Bitmask indicates when masking should be applyed or removed, - * None at all (rare - RFC 6455 expects masking in at least one - * direction), applied to frames we receive, or applied to frames - * we sent. Both is possible (but again rare - RFC 6455 indicates - * masking is only required on frames from the client/browser to the - * server. - */ -typedef enum { - WEB_SOCKET_MASKING_NONE = 0, - WEB_SOCKET_MASKING_RECV = 1, - WEB_SOCKET_MASKING_SEND = 1 << 1, -} WebSocketMaskingRequired; - -typedef enum { - ASYNCSOCKET_TYPE_SOCKET = 0, - ASYNCSOCKET_TYPE_NAMEDPIPE = 1, - ASYNCSOCKET_TYPE_PROXYSOCKET = 2, -} AsyncSocketType; - -/* - * Output buffer list data type, for the queue of outgoing buffers - */ -typedef struct SendBufList { - struct SendBufList *next; - void *buf; - int len; - AsyncSocketSendFn sendFn; - void *clientData; - /* - * If the data needs to be encoded somehow before sending over the - * wire, this will point to an internally-allocated buffer - * containing the encoded version of buf. The len field above will - * hold the length of the encoded data. - */ - char *encodedBuf; -} SendBufList; - -/* - * Callback to allow user handling of custom upgrade request headers - */ -typedef int (*AsyncWebSocketUpgradeRequestFn) (AsyncSocket *asock, - WebSocketHttpRequest *httpRequest); - -/* - * Callback to allow user handling of custom upgrade request headers - */ -typedef int (*AsyncWebSocketUpgradeResponseFn) (AsyncSocket *asock, - WebSocketHttpRequest *httpRequest); - -typedef enum { - CONNECTING_PRIMARY_SOCKET = 0, - CONNECTED_PRIMARY_SOCKET, - CONNECTING_SECONDARY_SOCKET, - CONNECTED_SECONDARY_SOCKET, -} AsyncProxySocketState; - -struct AsyncSocket { - uint32 id; - AsyncSocketState state; - int fd; - SSLSock sslSock; - AsyncSocketType asockType; - const struct AsyncSocketVTable *vt; - - unsigned int refCount; - int genericErrno; - AsyncSocketErrorFn errorFn; - void *errorClientData; - Bool errorSeen; - - struct sockaddr_storage localAddr; - socklen_t localAddrLen; - struct sockaddr_storage remoteAddr; - socklen_t remoteAddrLen; - - AsyncSocketConnectFn connectFn; - AsyncSocketRecvFn recvFn; - AsyncSocketSslAcceptFn sslAcceptFn; - AsyncSocketSslConnectFn sslConnectFn; - int sslPollFlags; /* shared by sslAcceptFn, sslConnectFn */ - - /* shared by recvFn, connectFn, sslAcceptFn and sslConnectFn */ - void *clientData; - - AsyncSocketPollParams pollParams; - PollerFunction internalConnectFn; - - /* governs optional AsyncSocket_Close() behavior */ - int flushEnabledMaxWaitMsec; - AsyncSocketCloseCb closeCb; - - void *recvBuf; - int recvPos; - int recvLen; - Bool recvCb; - Bool recvCbTimer; - Bool recvFireOnPartial; - - SendBufList *sendBufList; - SendBufList **sendBufTail; - int sendPos; - Bool sendCb; - Bool sendCbTimer; - Bool sendCbRT; - Bool sendBufFull; - Bool sendLowLatency; - - Bool sslConnected; - - uint8 inIPollCb; - Bool inRecvLoop; - uint32 inBlockingRecv; - - AsyncSocket *listenAsock4; - AsyncSocket *listenAsock6; - - struct { - Bool expected; - int fd; - } passFd; - - struct { - char *origin; - char *host; - char *hostname; - char *uri; - char *cookie; - int version; - WebSocketMaskingRequired maskingRequirements; - WebSocketFrameOpcode frameOpcode; - WebSocketState state; - void *connectClientData; - // Saved error reporting values. - AsyncSocketErrorFn errorFn; - void *errorClientData; - int webSocketError; - char *socketBuffer; // Accumulates incoming data (including framing etc.) - char *decodeBuffer; // Accumulates incoming data after removing framing - int32 socketBufferWriteOffset; - int32 socketBufferReadOffset; - int32 decodeBufferWriteOffset; - int32 decodeBufferReadOffset; - size_t frameBytesRemaining; - size_t frameSize; - Bool maskPresent; - uint8 maskBytes[4]; - uint8 maskOffset; - const char **streamProtocols; // null terminated list of protocols - const char *streamProtocol; // points to one of the above. - WebSocketDecodeState decodeState; - Bool useSSL; - void *sslCtx; // Optional SSL Context - SSLVerifyParam *sslVerifyParam; // Used for certificate verifications - char *upgradeNonceBase64; - rqContext *randomContext; - uint16 closeStatus; - AsyncWebSocketUpgradeRequestFn upgradeRequestPrepareFn; - AsyncWebSocketUpgradeResponseFn upgradeResponseProcessFn; - } webSocket; - - struct { - AsyncProxySocketState proxySocketState; - char *secondaryUrl; - char *e2ePort; - const char *secondaryIP; - char *secondaryPort; - SSLVerifyParam *secondarySslVerifyParam; - const char *akey; - const char *label; - void *privData; - struct TCP2SCTPListenerArg *tcp2sctp; - AsyncSocket *primarySocket; - AsyncSocket *secondarySocket; - } proxySocket; - -#ifdef _WIN32 - struct { - char *pipeName; - uint32 connectCount; - uint32 numInstances; - DWORD openMode; - DWORD pipeMode; - HANDLE pipe; - OVERLAPPED rd; - OVERLAPPED wr; - } namedPipe; -#endif - - struct { - struct VSockSocket *socket; - Bool signalCb; - Bool sendCb; - uint32 opMask; - void *partialRecvBuf; - uint32 partialRecvLen; - } vmci; -}; - -typedef struct AsyncSocketVTable { - AsyncSocketState (*getState)(AsyncSocket *sock); - int (*getGenericErrno)(AsyncSocket *s); - int (*getFd)(AsyncSocket *asock); - int (*getRemoteIPStr)(AsyncSocket *asock, const char **ipStr); - int (*getINETIPStr)(AsyncSocket *asock, int socketFamily, char **ipRetStr); - unsigned int (*getPort)(AsyncSocket *asock); - - int (*useNodelay)(AsyncSocket *asock, Bool nodelay); - int (*setTCPTimeouts)(AsyncSocket *asock, int keepIdle, int keepIntvl, - int keepCnt); - Bool (*setBufferSizes)(AsyncSocket *asock, int sendSz, int recvSz); - void (*setSendLowLatencyMode)(AsyncSocket *asock, Bool enable); - - Bool (*connectSSL)(AsyncSocket *asock, struct _SSLVerifyParam *verifyParam, - void *sslContext); - void (*startSslConnect)(AsyncSocket *asock, - struct _SSLVerifyParam *verifyParam, void *sslCtx, - AsyncSocketSslConnectFn sslConnectFn, - void *clientData); - Bool (*acceptSSL)(AsyncSocket *asock, void *sslCtx); - void (*startSslAccept)(AsyncSocket *asock, void *sslCtx, - AsyncSocketSslAcceptFn sslAcceptFn, - void *clientData); - int (*flush)(AsyncSocket *asock, int timeoutMS); - - int (*recv)(AsyncSocket *asock, void *buf, int len, Bool partial, void *cb, - void *cbData); - int (*recvPassedFd)(AsyncSocket *asock, void *buf, int len, void *cb, - void *cbData); - int (*getReceivedFd)(AsyncSocket *asock); - - int (*send)(AsyncSocket *asock, void *buf, int len, - AsyncSocketSendFn sendFn, void *clientData); - int (*isSendBufferFull)(AsyncSocket *asock); - - int (*close)(AsyncSocket *asock); - int (*cancelRecv)(AsyncSocket *asock, int *partialRecvd, void **recvBuf, - void **recvFn, Bool cancelOnSend); - void (*cancelCbForClose)(AsyncSocket *asock); - - int (*getLocalVMCIAddress)(AsyncSocket *asock, uint32 *cid, uint32 *port); - int (*getRemoteVMCIAddress)(AsyncSocket *asock, uint32 *cid, uint32 *port); - - // WebSocket Specific - char *(*getWebSocketURI)(AsyncSocket *asock); - char *(*getWebSocketCookie)(AsyncSocket *asock); - uint16 (*getWebSocketCloseStatus)(const AsyncSocket *asock); - const char *(*getWebSocketProtocol)(AsyncSocket *asock); - - // Internal - void (*dispatchConnect)(AsyncSocket *asock, AsyncSocket *newsock); - int (*prepareSend)(AsyncSocket *asock, void *buf, int len, - AsyncSocketSendFn sendFn, void *clientData, - Bool *bufferListWasEmpty); - int (*sendInternal)(AsyncSocket *asock, Bool bufferListWasEmpty, void *buf, - int len); - int (*recvInternal)(AsyncSocket *asock, void *buf, int len); - PollerFunction sendCallback; - PollerFunction recvCallback; - Bool (*hasDataPending)(AsyncSocket *asock); - void (*cancelListenCbInternal)(AsyncSocket *asock); - void (*cancelRecvCbInternal)(AsyncSocket *asock); - void (*cancelCbForCloseInternal)(AsyncSocket *asock); - Bool (*cancelCbForConnectingCloseInternal)(AsyncSocket *asock); - void (*closeInternal)(AsyncSocket *asock); - void (*release)(AsyncSocket *asock); -} AsyncSocketVTable; - -AsyncSocket *AsyncSocketInit(int socketFamily, - AsyncSocketPollParams *pollParams, - int *outError); -Bool AsyncSocketBind(AsyncSocket *asock, struct sockaddr_storage *addr, - socklen_t addrLen, int *outError); -Bool AsyncSocketListen(AsyncSocket *asock, AsyncSocketConnectFn connectFn, - void *clientData, int *outError); -int AsyncSocketResolveAddr(const char *hostname, - unsigned int port, - int family, - Bool passive, - struct sockaddr_storage *addr, - socklen_t *addrLen, - char **addrString); -AsyncSocket *AsyncSocketConnectWithAsock(AsyncSocket *asock, - struct sockaddr_storage *addr, - socklen_t addrLen, - AsyncSocketConnectFn connectFn, - void *clientData, - PollerFunction internalConnectFn, - AsyncSocketPollParams *pollParams, - int *outError); -int AsyncSocketAddRef(AsyncSocket *s); -int AsyncSocketRelease(AsyncSocket *s, Bool unlock); -void AsyncSocketLock(AsyncSocket *asock); -void AsyncSocketUnlock(AsyncSocket *asock); -Bool AsyncSocketIsLocked(AsyncSocket *asock); -void AsyncSocketHandleError(AsyncSocket *asock, int asockErr); -int AsyncSocketFillRecvBuffer(AsyncSocket *s); -void AsyncSocketDispatchSentBuffer(AsyncSocket *s); -Bool AsyncSocketCheckAndDispatchRecv(AsyncSocket *s, int *error); -int AsyncSocketSendInternal(AsyncSocket *asock, void *buf, int len, - AsyncSocketSendFn sendFn, void *clientData, - Bool *bufferListWasEmpty); -int AsyncSocketSendSocket(AsyncSocket *asock, Bool bufferListWasEmpty, - void *buf, int len); -void AsyncSocketSendCallback(void *clientData); -AsyncSocket *AsyncSocketCreate(AsyncSocketPollParams *pollParams); -void AsyncSocketDispatchConnect(AsyncSocket *asock, AsyncSocket *newsock); -void AsyncSocketRecvCallback(void *clientData); -int AsyncSocketRecvSocket(AsyncSocket *asock, void *buf, int len); -void AsyncSocketCancelListenCbSocket(AsyncSocket *asock); -void AsyncSocketCancelRecvCbSocket(AsyncSocket *asock); -void AsyncSocketCancelCbForCloseSocket(AsyncSocket *asock); -Bool AsyncSocketCancelCbForConnectingCloseSocket(AsyncSocket *asock); -void AsyncSocketCloseSocket(AsyncSocket *asock); -#ifndef VMX86_TOOLS -void AsyncSocketInitWebSocket(AsyncSocket *asock, - void *clientData, - Bool useSSL, - const char *protocols[], - void *sslCtx); -#endif -AsyncSocket *AsyncSocketListenImpl(struct sockaddr_storage *addr, - socklen_t addrLen, - AsyncSocketConnectFn connectFn, - void *clientData, - AsyncSocketPollParams *pollParams, - Bool isWebSock, - Bool webSockUseSSL, - const char *protocols[], - void *sslCtx, - int *outError); -AsyncSocket *AsyncSocketListenerCreate(const char *addrStr, - unsigned int port, - AsyncSocketConnectFn connectFn, - void *clientData, - AsyncSocketPollParams *pollParams, - Bool isWebSock, - Bool webSockUseSSL, - const char *protocols[], - void *sslCtx, - int *outError); -AsyncSocket *AsyncSocketListenerCreateImpl(const char *addrStr, - unsigned int port, - int socketFamily, - AsyncSocketConnectFn connectFn, - void *clientData, - AsyncSocketPollParams *pollParams, - Bool isWebSock, - Bool webSockUseSSL, - const char *protocols[], - void *sslCtx, - int *outError); - -AsyncSocketState AsyncSocketGetState(AsyncSocket *sock); -int AsyncSocketGetGenericErrno(AsyncSocket *s); -int AsyncSocketGetFd(AsyncSocket *asock); -int AsyncSocketGetRemoteIPStr(AsyncSocket *asock, const char **ipStr); -int AsyncSocketGetINETIPStr(AsyncSocket *asock, int socketFamily, - char **ipRetStr); -unsigned int AsyncSocketGetPort(AsyncSocket *asock); -int AsyncSocketUseNodelay(AsyncSocket *asock, Bool nodelay); -int AsyncSocketSetTCPTimeouts(AsyncSocket *asock, int keepIdle, - int keepIntvl, int keepCnt); -Bool AsyncSocketSetBufferSizes(AsyncSocket *asock, int sendSz, int recvSz); -void AsyncSocketSetSendLowLatencyMode(AsyncSocket *asock, Bool enable); -Bool AsyncSocketConnectSSL(AsyncSocket *asock, - struct _SSLVerifyParam *verifyParam, - void *sslContext); -void AsyncSocketStartSslConnect(AsyncSocket *asock, SSLVerifyParam *verifyParam, - void *sslCtx, - AsyncSocketSslConnectFn sslConnectFn, - void *clientData); -Bool AsyncSocketAcceptSSL(AsyncSocket *asock, void *sslCtx); -void AsyncSocketStartSslAccept(AsyncSocket *asock, void *sslCtx, - AsyncSocketSslAcceptFn sslAcceptFn, - void *clientData); -int AsyncSocketFlush(AsyncSocket *asock, int timeoutMS); - -int AsyncSocketRecv(AsyncSocket *asock, - void *buf, int len, Bool partial, void *cb, void *cbData); -int AsyncSocketRecvPassedFd(AsyncSocket *asock, void *buf, int len, - void *cb, void *cbData); -int AsyncSocketGetReceivedFd(AsyncSocket *asock); -int AsyncSocketSend(AsyncSocket *asock, void *buf, int len, - AsyncSocketSendFn sendFn, void *clientData); -int AsyncSocketIsSendBufferFull(AsyncSocket *asock); -int AsyncSocketClose(AsyncSocket *asock); -int AsyncSocketCancelRecv(AsyncSocket *asock, int *partialRecvd, - void **recvBuf, void **recvFn, Bool cancelOnSend); -void AsyncSocketCancelCbForClose(AsyncSocket *asock); -int AsyncSocketGetLocalVMCIAddress(AsyncSocket *asock, - uint32 *cid, uint32 *port); -int AsyncSocketGetRemoteVMCIAddress(AsyncSocket *asock, - uint32 *cid, uint32 *port); -char *AsyncSocketGetWebSocketURI(AsyncSocket *asock); -char *AsyncSocketGetWebSocketCookie(AsyncSocket *asock); -uint16 AsyncSocketGetWebSocketCloseStatus(const AsyncSocket *asock); -const char *AsyncSocketGetWebSocketProtocol(AsyncSocket *asock); - -/* - * Websocket Connect extension function. - */ -AsyncSocket * -AsyncSocket_ConnectWebSocketEx(const char *url, - struct _SSLVerifyParam *sslVerifyParam, - const char *proxyStr, - const char *cookies, - const char *protocols[], - AsyncSocketConnectFn connectFn, - void *clientData, - AsyncSocketConnectFlags flags, - AsyncSocketPollParams *pollParams, - AsyncWebSocketUpgradeRequestFn prepareRequestFn, - AsyncWebSocketUpgradeResponseFn processResponseFn, - void *privData, - int *error); - -/* - * Utilities for building and parsing http request/response strings. - */ -void WebSocketHttpRequestPrintf(WebSocketHttpRequest *request, - const char *format, ...); - -void WebSocketHttpRequestReset(WebSocketHttpRequest *request); -char *WebSocketHttpRequestGetHeader(const WebSocketHttpRequest *request, - const char *webKey); -Bool WebSocketHttpRequestHasHeader(const WebSocketHttpRequest *request, - const char *key); -char *WebSocketHttpRequestGetURI(const WebSocketHttpRequest *request); -char *WebSocketHttpRequestGetVerb(const WebSocketHttpRequest *request); -char *WebSocketHttpRequestGetPath(const WebSocketHttpRequest *request); - -#endif // __ASYNC_SOCKET_INT_H__ diff --git a/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c b/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c index 7d71275bb..b58bb4619 100644 --- a/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c +++ b/open-vm-tools/lib/asyncsocket/asyncSocketInterface.c @@ -49,8 +49,53 @@ * generally are NOT virtualized. */ +#include "vmware.h" #include "asyncsocket.h" -#include "asyncSocketInt.h" +#include "asyncSocketBase.h" +#include "msg.h" +#include "log.h" + +#define LOGLEVEL_MODULE asyncsocket +#include "loglevel_user.h" + + + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_SetCloseOptions -- + * + * Enables optional behavior for AsyncSocket_Close(): + * + * - If flushEnabledMaxWaitMsec is non-zero, the output stream + * will be flushed synchronously before the socket is closed. + * (default is zero: close socket right away without flushing) + * + * - If closeCb is set, the callback will be called asynchronously + * when the socket is actually destroyed. + * (default is NULL: no callback) + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +void +AsyncSocket_SetCloseOptions(AsyncSocket *asock, // IN + int flushEnabledMaxWaitMsec, // IN + AsyncSocketCloseFn closeCb) // IN +{ + if (VALID(asock, setCloseOptions)) { + AsyncSocketLock(asock); + VT(asock)->setCloseOptions(asock, flushEnabledMaxWaitMsec, closeCb); + AsyncSocketUnlock(asock); + } +} /* @@ -72,13 +117,17 @@ */ AsyncSocketState -AsyncSocket_GetState(AsyncSocket *asock) +AsyncSocket_GetState(AsyncSocket *asock) // IN { - if (!asock) { - return ASOCKERR_INVAL; + AsyncSocketState ret; + if (VALID(asock, getState)) { + AsyncSocketLock(asock); + ret = VT(asock)->getState(asock); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - ASSERT(asock->vt->getState); - return asock->vt->getState(asock); + return ret; } @@ -106,9 +155,15 @@ AsyncSocket_GetState(AsyncSocket *asock) int AsyncSocket_GetGenericErrno(AsyncSocket *asock) // IN: { - ASSERT(asock); - ASSERT(asock->vt->getGenericErrno); - return asock->vt->getGenericErrno(asock); + int ret; + if (VALID(asock, getGenericErrno)) { + AsyncSocketLock(asock); + ret = VT(asock)->getGenericErrno(asock); + AsyncSocketUnlock(asock); + } else { + ret = -1; + } + return ret; } @@ -129,10 +184,17 @@ AsyncSocket_GetGenericErrno(AsyncSocket *asock) // IN: */ int -AsyncSocket_GetFd(AsyncSocket *asock) +AsyncSocket_GetFd(AsyncSocket *asock) // IN { - ASSERT(asock->vt->getFd); - return asock->vt->getFd(asock); + int ret; + if (VALID(asock, getFd)) { + AsyncSocketLock(asock); + ret = VT(asock)->getFd(asock); + AsyncSocketUnlock(asock); + } else { + ret = -1; + } + return ret; } @@ -146,7 +208,7 @@ AsyncSocket_GetFd(AsyncSocket *asock) * connection. * * Results: - * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. + * ASOCKERR_SUCCESS or ASOCKERR_INVAL. * * Side effects: * @@ -158,9 +220,15 @@ int AsyncSocket_GetRemoteIPStr(AsyncSocket *asock, // IN const char **ipRetStr) // OUT { - ASSERT(asock); - ASSERT(asock->vt->getRemoteIPStr); - return asock->vt->getRemoteIPStr(asock, ipRetStr); + int ret; + if (VALID(asock, getRemoteIPStr)) { + AsyncSocketLock(asock); + ret = VT(asock)->getRemoteIPStr(asock, ipRetStr); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; } @@ -193,8 +261,15 @@ AsyncSocket_GetINETIPStr(AsyncSocket *asock, // IN int socketFamily, // IN char **ipRetStr) // OUT { - ASSERT(asock->vt->getINETIPStr); - return asock->vt->getINETIPStr(asock, socketFamily, ipRetStr); + int ret; + if (VALID(asock, getINETIPStr)) { + AsyncSocketLock(asock); + ret = VT(asock)->getINETIPStr(asock, socketFamily, ipRetStr); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; } @@ -218,8 +293,15 @@ AsyncSocket_GetINETIPStr(AsyncSocket *asock, // IN unsigned int AsyncSocket_GetPort(AsyncSocket *asock) // IN { - ASSERT(asock->vt->getPort); - return asock->vt->getPort(asock); + int ret; + if (VALID(asock, getPort)) { + AsyncSocketLock(asock); + ret = VT(asock)->getPort(asock); + AsyncSocketUnlock(asock); + } else { + ret = MAX_UINT32; + } + return ret; } @@ -232,7 +314,7 @@ AsyncSocket_GetPort(AsyncSocket *asock) // IN * enables Nagle's algorithm, respectively. * * Results: - * ASOCKERR_SUCCESS on success, ASOCKERR_GENERIC otherwise. + * ASOCKERR_SUCCESS on success, ASOCKERR_* otherwise. * * Side Effects: * Increased bandwidth usage for short messages on this socket @@ -245,8 +327,15 @@ int AsyncSocket_UseNodelay(AsyncSocket *asock, // IN/OUT: Bool nodelay) // IN: { - ASSERT(asock->vt->useNodelay); - return asock->vt->useNodelay(asock, nodelay); + int ret; + if (VALID(asock, useNodelay)) { + AsyncSocketLock(asock); + ret = VT(asock)->useNodelay(asock, nodelay); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; } @@ -267,7 +356,7 @@ AsyncSocket_UseNodelay(AsyncSocket *asock, // IN/OUT: * the connection if no response is received from the peer. * * Results: - * ASOCKERR_SUCCESS on success, ASOCKERR_GENERIC otherwise. + * ASOCKERR_SUCCESS on success, ASOCKERR_* otherwise. * * Side Effects: * None. @@ -275,17 +364,22 @@ AsyncSocket_UseNodelay(AsyncSocket *asock, // IN/OUT: *---------------------------------------------------------------------------- */ -#ifdef VMX86_SERVER int AsyncSocket_SetTCPTimeouts(AsyncSocket *asock, // IN/OUT: int keepIdle, // IN int keepIntvl, // IN int keepCnt) // IN { - ASSERT(asock->vt->setTCPTimeouts); - return asock->vt->setTCPTimeouts(asock, keepIdle, keepIntvl, keepCnt); + int ret; + if (VALID(asock, setTCPTimeouts)) { + AsyncSocketLock(asock); + ret = VT(asock)->setTCPTimeouts(asock, keepIdle, keepIntvl, keepCnt); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; } -#endif /* @@ -310,11 +404,15 @@ AsyncSocket_SetBufferSizes(AsyncSocket *asock, // IN int sendSz, // IN int recvSz) // IN { - if (!asock) { - return FALSE; + Bool ret; + if (VALID(asock, setBufferSizes)) { + AsyncSocketLock(asock); + ret = VT(asock)->setBufferSizes(asock, sendSz, recvSz); + AsyncSocketUnlock(asock); + } else { + ret = FALSE; } - ASSERT(asock->vt->setBufferSizes); - return asock->vt->setBufferSizes(asock, sendSz, recvSz); + return ret; } @@ -346,8 +444,11 @@ void AsyncSocket_SetSendLowLatencyMode(AsyncSocket *asock, // IN Bool enable) // IN { - ASSERT(asock->vt->setSendLowLatencyMode); - asock->vt->setSendLowLatencyMode(asock, enable); + if (VALID(asock, setSendLowLatencyMode)) { + AsyncSocketLock(asock); + VT(asock)->setSendLowLatencyMode(asock, enable); + AsyncSocketUnlock(asock); + } } @@ -380,10 +481,12 @@ AsyncSocket_StartSslConnect(AsyncSocket *asock, // IN AsyncSocketSslConnectFn sslConnectFn, // IN void *clientData) // IN { - ASSERT(asock); - ASSERT(asock->vt->startSslConnect); - asock->vt->startSslConnect(asock, verifyParam, sslCtx, sslConnectFn, - clientData); + if (VALID(asock, startSslConnect)) { + AsyncSocketLock(asock); + VT(asock)->startSslConnect(asock, verifyParam, sslCtx, sslConnectFn, + clientData); + AsyncSocketUnlock(asock); + } } @@ -409,9 +512,15 @@ AsyncSocket_ConnectSSL(AsyncSocket *asock, // IN SSLVerifyParam *verifyParam, // IN/OPT void *sslContext) // IN/OPT { - ASSERT(asock); - ASSERT(asock->vt->connectSSL); - return asock->vt->connectSSL(asock, verifyParam, sslContext); + Bool ret; + if (VALID(asock, connectSSL)) { + AsyncSocketLock(asock); + ret = VT(asock)->connectSSL(asock, verifyParam, sslContext); + AsyncSocketUnlock(asock); + } else { + ret = FALSE; + } + return ret; } @@ -435,12 +544,17 @@ Bool AsyncSocket_AcceptSSL(AsyncSocket *asock, // IN void *sslCtx) // IN: optional { - ASSERT(asock); - ASSERT(asock->vt->acceptSSL); - return asock->vt->acceptSSL(asock, sslCtx); + Bool ret; + if (VALID(asock, acceptSSL)) { + AsyncSocketLock(asock); + ret = VT(asock)->acceptSSL(asock, sslCtx); + AsyncSocketUnlock(asock); + } else { + ret = FALSE; + } + return ret; } - /* *----------------------------------------------------------------------------- * @@ -467,9 +581,11 @@ AsyncSocket_StartSslAccept(AsyncSocket *asock, // IN AsyncSocketSslAcceptFn sslAcceptFn, // IN void *clientData) // IN { - ASSERT(asock); - ASSERT(asock->vt->startSslAccept); - asock->vt->startSslAccept(asock, sslCtx, sslAcceptFn, clientData); + if (VALID(asock, startSslAccept)) { + AsyncSocketLock(asock); + VT(asock)->startSslAccept(asock, sslCtx, sslAcceptFn, clientData); + AsyncSocketUnlock(asock); + } } @@ -484,7 +600,8 @@ AsyncSocket_StartSslAccept(AsyncSocket *asock, // IN * Results: * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call * failures, and ASOCKERR_TIMEOUT if we couldn't send enough data - * before the timeout expired. + * before the timeout expired. ASOCKERR_INVAL on invalid + * parameters or operation not implemented on this socket. * * Side effects: * None. @@ -495,12 +612,15 @@ int AsyncSocket_Flush(AsyncSocket *asock, // IN int timeoutMS) // IN { - if (asock == NULL) { - Warning(ASOCKPREFIX "Flush called with invalid arguments!\n"); - return ASOCKERR_INVAL; + int ret; + if (VALID(asock, flush)) { + AsyncSocketLock(asock); + ret = VT(asock)->flush(asock, timeoutMS); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - ASSERT(asock->vt->flush); - return asock->vt->flush(asock, timeoutMS); + return ret; } @@ -533,30 +653,39 @@ AsyncSocket_Flush(AsyncSocket *asock, // IN */ int -AsyncSocket_Recv(AsyncSocket *asock, - void *buf, - int len, - void *cb, - void *cbData) +AsyncSocket_Recv(AsyncSocket *asock, // IN + void *buf, // IN (buffer to fill) + int len, // IN + void *cb, // IN + void *cbData) // IN { - ASSERT(asock->vt->recv); - if (!asock) { - Warning(ASOCKPREFIX "Recv called with invalid arguments!\n"); - return ASOCKERR_INVAL; + int ret; + if (VALID(asock, recv)) { + AsyncSocketLock(asock); + ret = VT(asock)->recv(asock, buf, len, FALSE, cb, cbData); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - - return asock->vt->recv(asock, buf, len, FALSE, cb, cbData); + return ret; } int -AsyncSocket_RecvPartial(AsyncSocket *asock, - void *buf, - int len, - void *cb, - void *cbData) +AsyncSocket_RecvPartial(AsyncSocket *asock, // IN + void *buf, // IN (buffer to fill) + int len, // IN + void *cb, // IN + void *cbData) // IN { - ASSERT(asock->vt->recv); - return asock->vt->recv(asock, buf, len, TRUE, cb, cbData); + int ret; + if (VALID(asock, recv)) { + AsyncSocketLock(asock); + ret = VT(asock)->recv(asock, buf, len, TRUE, cb, cbData); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; } @@ -584,13 +713,15 @@ AsyncSocket_RecvPassedFd(AsyncSocket *asock, // IN/OUT: socket void *cb, // IN: completion calback void *cbData) // IN: callback's data { - if (!asock) { - Warning(ASOCKPREFIX "Recv called with invalid arguments!\n"); - return ASOCKERR_INVAL; + int ret; + if (VALID(asock, recvPassedFd)) { + AsyncSocketLock(asock); + ret = VT(asock)->recvPassedFd(asock, buf, len, cb, cbData); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - - ASSERT(asock->vt->recvPassedFd); - return asock->vt->recvPassedFd(asock, buf, len, cb, cbData); + return ret; } @@ -613,13 +744,15 @@ AsyncSocket_RecvPassedFd(AsyncSocket *asock, // IN/OUT: socket int AsyncSocket_GetReceivedFd(AsyncSocket *asock) // IN { - if (!asock) { - Warning(ASOCKPREFIX "Invalid socket while receiving fd!\n"); - return -1; + int ret; + if (VALID(asock, getReceivedFd)) { + AsyncSocketLock(asock); + ret = VT(asock)->getReceivedFd(asock); + AsyncSocketUnlock(asock); + } else { + ret = -1; } - - ASSERT(asock->vt->getReceivedFd); - return asock->vt->getReceivedFd(asock); + return ret; } @@ -651,19 +784,21 @@ AsyncSocket_GetReceivedFd(AsyncSocket *asock) // IN */ int -AsyncSocket_Send(AsyncSocket *asock, - void *buf, - int len, - AsyncSocketSendFn sendFn, - void *clientData) +AsyncSocket_Send(AsyncSocket *asock, // IN + void *buf, // IN + int len, // IN + AsyncSocketSendFn sendFn, // IN + void *clientData) // IN { - if (!asock || !buf || len <= 0) { - Warning(ASOCKPREFIX "Send called with invalid arguments! asynchSock: %p " - "buffer: %p length: %d\n", asock, buf, len); - return ASOCKERR_INVAL; + int ret; + if (VALID(asock, send)) { + AsyncSocketLock(asock); + ret = VT(asock)->send(asock, buf, len, sendFn, clientData); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - ASSERT(asock->vt->send); - return asock->vt->send(asock, buf, len, sendFn, clientData); + return ret; } @@ -679,7 +814,7 @@ AsyncSocket_Send(AsyncSocket *asock, * Results: * 0: send space probably available, * 1: send has reached maximum, - * ASOCKERR_GENERIC: null socket. + * ASOCKERR_INVAL: null socket or operation not supported. * * Side effects: * None. @@ -688,13 +823,49 @@ AsyncSocket_Send(AsyncSocket *asock, */ int -AsyncSocket_IsSendBufferFull(AsyncSocket *asock) +AsyncSocket_IsSendBufferFull(AsyncSocket *asock) // IN { - if (!asock) { - return ASOCKERR_GENERIC; + int ret; + if (VALID(asock, isSendBufferFull)) { + AsyncSocketLock(asock); + ret = VT(asock)->isSendBufferFull(asock); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - ASSERT(asock->vt->isSendBufferFull); - return asock->vt->isSendBufferFull(asock); + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_GetNetworkStats -- + * + * Get network statistics from the active socket. + * + * Results: + * ASOCKERR_* + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_GetNetworkStats(AsyncSocket *asock, // IN + AsyncSocketNetworkStats *stats) // OUT +{ + int ret; + if (VALID(asock, getNetworkStats)) { + AsyncSocketLock(asock); + ret = VT(asock)->getNetworkStats(asock, stats); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; } @@ -720,13 +891,18 @@ AsyncSocket_IsSendBufferFull(AsyncSocket *asock) */ int -AsyncSocket_Close(AsyncSocket *asock) +AsyncSocket_Close(AsyncSocket *asock) // IN { - if (!asock) { - return ASOCKERR_INVAL; + int ret; + if (VALID(asock, close)) { + AsyncSocketLock(asock); + ret = VT(asock)->close(asock); + AsyncSocketRelease(asock); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - ASSERT(asock->vt->close); - return asock->vt->close(asock); + return ret; } @@ -768,13 +944,16 @@ AsyncSocket_CancelRecvEx(AsyncSocket *asock, // IN void **recvFn, // OUT Bool cancelOnSend) // IN { - if (!asock) { - Warning(ASOCKPREFIX "Invalid socket while cancelling recv request!\n"); - return ASOCKERR_INVAL; + int ret; + if (VALID(asock, cancelRecv)) { + AsyncSocketLock(asock); + ret = VT(asock)->cancelRecv(asock, partialRecvd, recvBuf, recvFn, + cancelOnSend); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - ASSERT(asock->vt->cancelRecv); - return asock->vt->cancelRecv(asock, partialRecvd, recvBuf, recvFn, - cancelOnSend); + return ret; } @@ -799,8 +978,11 @@ AsyncSocket_CancelRecvEx(AsyncSocket *asock, // IN void AsyncSocket_CancelCbForClose(AsyncSocket *asock) // IN: { - ASSERT(asock->vt->cancelCbForClose); - asock->vt->cancelCbForClose(asock); + if (VALID(asock, cancelCbForClose)) { + AsyncSocketLock(asock); + VT(asock)->cancelCbForClose(asock); + AsyncSocketUnlock(asock); + } } @@ -827,9 +1009,15 @@ AsyncSocket_GetLocalVMCIAddress(AsyncSocket *asock, // IN uint32 *cid, // OUT: optional uint32 *port) // OUT: optional { - ASSERT(asock); - ASSERT(asock->vt->getLocalVMCIAddress); - return asock->vt->getLocalVMCIAddress(asock, cid, port); + int ret; + if (VALID(asock, getLocalVMCIAddress)) { + AsyncSocketLock(asock); + ret = VT(asock)->getLocalVMCIAddress(asock, cid, port); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; } @@ -856,9 +1044,47 @@ AsyncSocket_GetRemoteVMCIAddress(AsyncSocket *asock, // IN uint32 *cid, // OUT: optional uint32 *port) // OUT: optional { - ASSERT(asock); - ASSERT(asock->vt->getRemoteVMCIAddress); - return asock->vt->getRemoteVMCIAddress(asock, cid, port); + int ret; + if (VALID(asock, getRemoteVMCIAddress)) { + AsyncSocketLock(asock); + ret = VT(asock)->getRemoteVMCIAddress(asock, cid, port); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_GetWebSocketError -- + * + * Return the HTTP error code supplied during a failed WebSocket + * upgrade negotiation. + * + * Results: + * Numeric HTTP error code, 0 if no error, or -1 on invalid arguments. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_GetWebSocketError(AsyncSocket *asock) // IN +{ + int ret; + if (VALID(asock, getWebSocketError)) { + AsyncSocketLock(asock); + ret = VT(asock)->getWebSocketError(asock); + AsyncSocketUnlock(asock); + } else { + ret = -1; + } + return ret; } @@ -881,9 +1107,15 @@ AsyncSocket_GetRemoteVMCIAddress(AsyncSocket *asock, // IN char * AsyncSocket_GetWebSocketURI(AsyncSocket *asock) // IN { - ASSERT(asock); - ASSERT(asock->vt->getWebSocketURI); - return asock->vt->getWebSocketURI(asock); + char *ret; + if (VALID(asock, getWebSocketURI)) { + AsyncSocketLock(asock); + ret = VT(asock)->getWebSocketURI(asock); + AsyncSocketUnlock(asock); + } else { + ret = NULL; + } + return ret; } @@ -908,11 +1140,15 @@ AsyncSocket_GetWebSocketURI(AsyncSocket *asock) // IN char * AsyncSocket_GetWebSocketCookie(AsyncSocket *asock) // IN { - ASSERT(asock); - if (asock->vt->getWebSocketCookie) { - return asock->vt->getWebSocketCookie(asock); + char *ret; + if (VALID(asock, getWebSocketCookie)) { + AsyncSocketLock(asock); + ret = VT(asock)->getWebSocketCookie(asock); + AsyncSocketUnlock(asock); + } else { + ret = NULL; } - return NULL; + return ret; } @@ -933,11 +1169,17 @@ AsyncSocket_GetWebSocketCookie(AsyncSocket *asock) // IN */ uint16 -AsyncSocket_GetWebSocketCloseStatus(const AsyncSocket *asock) // IN +AsyncSocket_GetWebSocketCloseStatus(AsyncSocket *asock) // IN { - ASSERT(asock); - ASSERT(asock->vt->getWebSocketCloseStatus); - return asock->vt->getWebSocketCloseStatus(asock); + uint16 ret; + if (VALID(asock, getWebSocketCloseStatus)) { + AsyncSocketLock(asock); + ret = VT(asock)->getWebSocketCloseStatus(asock); + AsyncSocketUnlock(asock); + } else { + ret = 0; + } + return ret; } @@ -962,9 +1204,199 @@ AsyncSocket_GetWebSocketCloseStatus(const AsyncSocket *asock) // IN const char * AsyncSocket_GetWebSocketProtocol(AsyncSocket *asock) // IN { - ASSERT(asock); - if (asock->vt->getWebSocketProtocol) { - return asock->vt->getWebSocketProtocol(asock); + const char *ret; + if (VALID(asock, getWebSocketProtocol)) { + AsyncSocketLock(asock); + ret = VT(asock)->getWebSocketProtocol(asock); + AsyncSocketUnlock(asock); + } else { + ret = NULL; + } + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_RecvBlocking -- + * + * Implement "blocking + timeout" operations on the socket. These are + * simple wrappers around the AsyncTCPSocketBlockingWork function, which + * operates on the actual non-blocking socket, using poll to determine + * when it's ok to keep reading/writing. If we can't finish within the + * specified time, we give up and return the ASOCKERR_TIMEOUT error. + * + * Note that if these are called from a callback and a lock is being + * used (pollParams.lock), the whole blocking operation takes place + * with that lock held. Regardless, it is the caller's responsibility + * to make sure the synchronous and asynchronous operations do not mix. + * + * Results: + * ASOCKERR_SUCCESS if we finished the operation, ASOCKERR_* error codes + * otherwise. + * + * Side effects: + * Reads/writes the socket. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_RecvBlocking(AsyncSocket *asock, // IN + void *buf, // OUT + int len, // IN + int *received, // OUT + int timeoutMS) // IN +{ + int ret; + if (VALID(asock, recvBlocking)) { + AsyncSocketLock(asock); + ret = VT(asock)->recvBlocking(asock, buf, len, received, timeoutMS); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_RecvPartialBlocking -- + * + * Implement "blocking + timeout" version of RecvPartial + * + * Results: + * ASOCKERR_SUCCESS if we finished the operation, ASOCKERR_* error codes + * otherwise. + * + * Side effects: + * Reads/writes the socket. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_RecvPartialBlocking(AsyncSocket *asock, // IN + void *buf, // OUT + int len, // IN + int *received, // OUT + int timeoutMS) // IN +{ + int ret; + if (VALID(asock, recvPartialBlocking)) { + AsyncSocketLock(asock); + ret = VT(asock)->recvPartialBlocking(asock, buf, len, received, + timeoutMS); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_SendBlocking -- + * + * Implement "blocking + timeout" version of Send + * + * Results: + * ASOCKERR_SUCCESS if we finished the operation, ASOCKERR_* error codes + * otherwise. + * + * Side effects: + * Reads/writes the socket. + * + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_SendBlocking(AsyncSocket *asock, // IN + void *buf, // IN + int len, // IN + int *sent, // OUT + int timeoutMS) // IN +{ + int ret; + if (VALID(asock, sendBlocking)) { + AsyncSocketLock(asock); + ret = VT(asock)->sendBlocking(asock, buf, len, sent, timeoutMS); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_DoOneMsg -- + * + * Spins a socket until the specified amount of time has elapsed or + * data has arrived / been sent. + * + * Results: + * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on system call + * failures + * ASOCKERR_TIMEOUT if nothing happened in the allotted time. + * + * Side effects: + * None. + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_DoOneMsg(AsyncSocket *asock, // IN + Bool read, // IN + int timeoutMS) // IN +{ + int ret; + if (VALID(asock, doOneMsg)) { + AsyncSocketLock(asock); + ret = VT(asock)->doOneMsg(asock, read, timeoutMS); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; + } + return ret; +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_WaitForConnection -- + * + * Spins a socket currently listening or connecting until the + * connection completes or the allowed time elapses. + * + * Results: + * ASOCKERR_SUCCESS if it worked, ASOCKERR_GENERIC on failures, and + * ASOCKERR_TIMEOUT if nothing happened in the allotted time. + * + * Side effects: + * None. + *---------------------------------------------------------------------------- + */ + +int +AsyncSocket_WaitForConnection(AsyncSocket *asock, // IN + int timeoutMS) // IN +{ + int ret; + if (VALID(asock, waitForConnection)) { + AsyncSocketLock(asock); + ret = VT(asock)->waitForConnection(asock, timeoutMS); + AsyncSocketUnlock(asock); + } else { + ret = ASOCKERR_INVAL; } - return NULL; + return ret; } diff --git a/open-vm-tools/lib/asyncsocket/asyncSocketVTable.h b/open-vm-tools/lib/asyncsocket/asyncSocketVTable.h new file mode 100644 index 000000000..022846001 --- /dev/null +++ b/open-vm-tools/lib/asyncsocket/asyncSocketVTable.h @@ -0,0 +1,110 @@ +/********************************************************* + * Copyright (C) 2011,2014-2016 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. + * + *********************************************************/ + +/********************************************************* + * The contents of this file are subject to the terms of the Common + * Development and Distribution License (the "License") version 1.0 + * and no later version. You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at + * http://www.opensource.org/licenses/cddl1.php + * + * See the License for the specific language governing permissions + * and limitations under the License. + * + *********************************************************/ + +#ifndef __ASYNC_SOCKET_VTABLE_H__ +#define __ASYNC_SOCKET_VTABLE_H__ + +#ifdef USE_SSL_DIRECT +#include "sslDirect.h" +#else +#include "ssl.h" +#endif + + +typedef struct AsyncSocketVTable { + AsyncSocketState (*getState)(AsyncSocket *sock); + int (*getGenericErrno)(AsyncSocket *s); + int (*getFd)(AsyncSocket *asock); + int (*getRemoteIPStr)(AsyncSocket *asock, const char **ipStr); + int (*getINETIPStr)(AsyncSocket *asock, int socketFamily, char **ipRetStr); + unsigned int (*getPort)(AsyncSocket *asock); + int (*useNodelay)(AsyncSocket *asock, Bool nodelay); + int (*setTCPTimeouts)(AsyncSocket *asock, int keepIdle, int keepIntvl, + int keepCnt); + Bool (*setBufferSizes)(AsyncSocket *asock, int sendSz, int recvSz); + void (*setSendLowLatencyMode)(AsyncSocket *asock, Bool enable); + void (*setCloseOptions)(AsyncSocket *asock, int flushEnabledMaxWaitMsec, + AsyncSocketCloseFn closeCb); + Bool (*connectSSL)(AsyncSocket *asock, struct _SSLVerifyParam *verifyParam, + void *sslContext); + void (*startSslConnect)(AsyncSocket *asock, + struct _SSLVerifyParam *verifyParam, void *sslCtx, + AsyncSocketSslConnectFn sslConnectFn, + void *clientData); + Bool (*acceptSSL)(AsyncSocket *asock, void *sslCtx); + void (*startSslAccept)(AsyncSocket *asock, void *sslCtx, + AsyncSocketSslAcceptFn sslAcceptFn, + void *clientData); + int (*flush)(AsyncSocket *asock, int timeoutMS); + int (*recv)(AsyncSocket *asock, void *buf, int len, Bool partial, void *cb, + void *cbData); + int (*recvPassedFd)(AsyncSocket *asock, void *buf, int len, void *cb, + void *cbData); + int (*getReceivedFd)(AsyncSocket *asock); + int (*send)(AsyncSocket *asock, void *buf, int len, + AsyncSocketSendFn sendFn, void *clientData); + int (*isSendBufferFull)(AsyncSocket *asock); + int (*getNetworkStats)(AsyncSocket *asock, + AsyncSocketNetworkStats *stats); + int (*close)(AsyncSocket *asock); + int (*cancelRecv)(AsyncSocket *asock, int *partialRecvd, void **recvBuf, + void **recvFn, Bool cancelOnSend); + void (*cancelCbForClose)(AsyncSocket *asock); + int (*getLocalVMCIAddress)(AsyncSocket *asock, uint32 *cid, uint32 *port); + int (*getRemoteVMCIAddress)(AsyncSocket *asock, uint32 *cid, uint32 *port); + int (*getWebSocketError)(AsyncSocket *asock); + char *(*getWebSocketURI)(AsyncSocket *asock); + char *(*getWebSocketCookie)(AsyncSocket *asock); + uint16 (*getWebSocketCloseStatus)(AsyncSocket *asock); + const char *(*getWebSocketProtocol)(AsyncSocket *asock); + int (*recvBlocking)(AsyncSocket *s, void *buf, int len, int *received, + int timeoutMS); + int (*recvPartialBlocking)(AsyncSocket *s, void *buf, int len, + int *received, int timeoutMS); + int (*sendBlocking)(AsyncSocket *s, void *buf, int len, int *sent, + int timeoutMS); + int (*doOneMsg)(AsyncSocket *s, Bool read, int timeoutMS); + int (*waitForConnection)(AsyncSocket *s, int timeoutMS); // IN: + + + /* + * Internal function, called when refcount drops to zero: + */ + void (*destroy)(AsyncSocket *asock); +} AsyncSocketVTable; + + +#define VT(x) ((x)->vt) +#define VALID(asock, x) LIKELY(asock && VT(asock)->x) + + +#endif diff --git a/open-vm-tools/lib/asyncsocket/asyncsocket.c b/open-vm-tools/lib/asyncsocket/asyncsocket.c index efb851e2d..a65670918 100644 --- a/open-vm-tools/lib/asyncsocket/asyncsocket.c +++ b/open-vm-tools/lib/asyncsocket/asyncsocket.c @@ -33,7 +33,7 @@ /* * asyncsocket.c -- * - * The AsyncSocket object is a fairly simple wrapper around a basic TCP + * The AsyncTCPSocket object is a fairly simple wrapper around a basic TCP * socket. It's potentially asynchronous for both read and write * operations. Reads are "requested" by registering a receive function * that is called once the requested amount of data has been read from @@ -47,11 +47,45 @@ #include #include -#include "str.h" +#ifdef _WIN32 +/* + * We redefine strcpy/strcat because the Windows SDK uses it for getaddrinfo(). + * When we upgrade SDKs, this redefinition can go away. + * Note: Now we are checking if we have secure libs for string operations + */ +#if !(defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L) +#define strcpy(dst,src) Str_Strcpy((dst), (src), 0x7FFFFFFF) +#define strcat(dst,src) Str_Strcat((dst), (src), 0x7FFFFFFF) +#endif +#include +#include +#include +#include +#include +#if !(defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L) +#undef strcpy +#undef strcat +#endif +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif #include "vmware.h" +#include "str.h" +#include "random.h" #include "asyncsocket.h" -#include "asyncSocketInt.h" +#include "asyncSocketBase.h" #include "poll.h" #include "log.h" #include "err.h" @@ -64,6 +98,14 @@ #include "vmdblib.h" #endif + +#ifdef _WIN32 +#define ASOCK_LASTERROR() WSAGetLastError() +#else +#define ASOCK_LASTERROR() errno +#endif + + #define LOGLEVEL_MODULE asyncsocket #include "loglevel_user.h" @@ -109,206 +151,391 @@ */ #define ADDR_STRING_LEN (INET6_ADDRSTRLEN + 2 + PORT_STRING_LEN) + /* - * The slots each have a "unique" ID, which is just an incrementing integer. + * Output buffer list data type, for the queue of outgoing buffers */ -static Atomic_uint32 nextid = { 1 }; +typedef struct SendBufList { + struct SendBufList *next; + void *buf; + int len; + AsyncSocketSendFn sendFn; + void *clientData; +} SendBufList; + + +typedef struct AsyncTCPSocket { + /* + * The base class, which is just a vtable: + */ + AsyncSocket base; + + /* + * Everything for the TCP AsyncSocket implementation: + */ + int fd; + SSLSock sslSock; + + int genericErrno; + + struct sockaddr_storage localAddr; + socklen_t localAddrLen; + struct sockaddr_storage remoteAddr; + socklen_t remoteAddrLen; + + AsyncSocketConnectFn connectFn; + AsyncSocketSslAcceptFn sslAcceptFn; + AsyncSocketSslConnectFn sslConnectFn; + int sslPollFlags; /* shared by sslAcceptFn, sslConnectFn */ + + /* shared by connectFn, sslAcceptFn and sslConnectFn */ + void *clientData; + + PollerFunction internalConnectFn; + PollerFunction internalSendFn; + PollerFunction internalRecvFn; + + /* governs optional AsyncSocket_Close() behavior */ + int flushEnabledMaxWaitMsec; + AsyncSocketCloseFn closeCb; + void *closeCbData; + + Bool recvCb; + Bool recvCbTimer; + + SendBufList *sendBufList; + SendBufList **sendBufTail; + int sendPos; + Bool sendCb; + Bool sendCbTimer; + Bool sendCbRT; + Bool sendBufFull; + Bool sendLowLatency; + + Bool sslConnected; + + uint8 inIPollCb; + Bool inRecvLoop; + Bool inDoOneMsg; + uint32 inBlockingRecv; + + struct AsyncTCPSocket *listenAsock4; + struct AsyncTCPSocket *listenAsock6; + + struct { + Bool expected; + int fd; + } passFd; + +} AsyncTCPSocket; + + /* * Local Functions */ -static Bool AsyncSocketHasDataPending(AsyncSocket *asock); -static int AsyncSocketMakeNonBlocking(int fd); -static void AsyncSocketAcceptCallback(void *clientData); -static void AsyncSocketConnectCallback(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, - int flags, PollerFunction callback, - ...); -static Bool AsyncSocketPollRemove(AsyncSocket *asock, Bool socket, - int flags, PollerFunction callback); -static unsigned int AsyncSocketGetPortFromAddr(struct sockaddr_storage *addr); -static AsyncSocket *AsyncSocketConnect(struct sockaddr_storage *addr, - socklen_t addrLen, - AsyncSocketConnectFn connectFn, - void *clientData, - AsyncSocketConnectFlags flags, - AsyncSocketPollParams *pollParams, - int *outError); -static int AsyncSocketConnectInternal(AsyncSocket *s); -static Bool AsyncSocketHasDataPendingSocket(AsyncSocket *asock); - -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 Bool AsyncSocketAddListenCbSocket(AsyncSocket *asock); -static void AsyncSocketSslConnectCallback(void *clientData); -static void AsyncSocketSslAcceptCallback(void *clientData); - -static const AsyncSocketVTable asyncStreamSocketVTable = { - AsyncSocketGetState, - AsyncSocketGetGenericErrno, - AsyncSocketGetFd, - AsyncSocketGetRemoteIPStr, - AsyncSocketGetINETIPStr, - AsyncSocketGetPort, - AsyncSocketUseNodelay, - AsyncSocketSetTCPTimeouts, - AsyncSocketSetBufferSizes, - AsyncSocketSetSendLowLatencyMode, - AsyncSocketConnectSSL, - AsyncSocketStartSslConnect, - AsyncSocketAcceptSSL, - AsyncSocketStartSslAccept, - AsyncSocketFlush, - AsyncSocketRecv, - AsyncSocketRecvPassedFd, - AsyncSocketGetReceivedFd, - AsyncSocketSend, - AsyncSocketIsSendBufferFull, - AsyncSocketClose, - AsyncSocketCancelRecv, - AsyncSocketCancelCbForClose, - AsyncSocketGetLocalVMCIAddress, - AsyncSocketGetRemoteVMCIAddress, - NULL, - NULL, - NULL, - NULL, - AsyncSocketDispatchConnect, - AsyncSocketSendInternal, - AsyncSocketSendSocket, - AsyncSocketRecvSocket, - AsyncSocketSendCallback, - AsyncSocketRecvCallback, - AsyncSocketHasDataPendingSocket, - AsyncSocketCancelListenCbSocket, - AsyncSocketCancelRecvCbSocket, - AsyncSocketCancelCbForCloseSocket, - AsyncSocketCancelCbForConnectingCloseSocket, - AsyncSocketCloseSocket, - NULL, -}; - -static const AsyncSocketVTable asyncStreamSocketIPollVTable = { +static AsyncTCPSocket *AsyncTCPSocketCreate(AsyncSocketPollParams *pollParams); +static void AsyncTCPSocketSendCallback(void *clientData); +static void AsyncTCPSocketRecvCallback(void *clientData); +static int AsyncTCPSocketResolveAddr(const char *hostname, + unsigned int port, + int family, + Bool passive, + struct sockaddr_storage *addr, + socklen_t *addrLen, + char **addrString); +static AsyncTCPSocket *AsyncTCPSocketAttachToFd( + int fd, AsyncSocketPollParams *pollParams, int *outError); +static Bool AsyncTCPSocketHasDataPending(AsyncTCPSocket *asock); +static int AsyncTCPSocketMakeNonBlocking(int fd); +static void AsyncTCPSocketAcceptCallback(void *clientData); +static void AsyncTCPSocketConnectCallback(void *clientData); +static int AsyncTCPSocketBlockingWork(AsyncTCPSocket *asock, Bool read, + void *buf, int len, + int *completed, int timeoutMS, + Bool partial); +static VMwareStatus AsyncTCPSocketPollAdd(AsyncTCPSocket *asock, Bool socket, + int flags, PollerFunction callback, + ...); +static Bool AsyncTCPSocketPollRemove(AsyncTCPSocket *asock, Bool socket, + int flags, PollerFunction callback); +static unsigned int AsyncTCPSocketGetPortFromAddr( + struct sockaddr_storage *addr); +static AsyncTCPSocket *AsyncTCPSocketConnect(struct sockaddr_storage *addr, + socklen_t addrLen, + AsyncSocketConnectFn connectFn, + void *clientData, + AsyncSocketConnectFlags flags, + AsyncSocketPollParams *pollParams, + int *outError); +static int AsyncTCPSocketConnectInternal(AsyncTCPSocket *s); + +static VMwareStatus AsyncTCPSocketIPollAdd(AsyncTCPSocket *asock, Bool socket, + int flags, PollerFunction callback, + int info); +static Bool AsyncTCPSocketIPollRemove(AsyncTCPSocket *asock, Bool socket, + int flags, PollerFunction callback); +static void AsyncTCPSocketIPollSendCallback(void *clientData); +static void AsyncTCPSocketIPollRecvCallback(void *clientData); +static Bool AsyncTCPSocketAddListenCb(AsyncTCPSocket *asock); +static void AsyncTCPSocketSslConnectCallback(void *clientData); +static void AsyncTCPSocketSslAcceptCallback(void *clientData); + +static Bool AsyncTCPSocketBind(AsyncTCPSocket *asock, + struct sockaddr_storage *addr, + socklen_t addrLen, + int *outError); +static Bool AsyncTCPSocketListen(AsyncTCPSocket *asock, + AsyncSocketConnectFn connectFn, + void *clientData, + int *outError); +static AsyncTCPSocket *AsyncTCPSocketInit(int socketFamily, + AsyncSocketPollParams *pollParams, + int *outError); + +static void AsyncTCPSocketCancelListenCb(AsyncTCPSocket *asock); + + +static int AsyncTCPSocketRegisterRecvCb(AsyncTCPSocket *asock); +static Bool AsyncTCPSocketCancelCbForConnectingClose(AsyncTCPSocket *asock); + +static int AsyncTCPSocketWaitForConnection(AsyncSocket *s, int timeoutMS); +static int AsyncTCPSocketGetGenericErrno(AsyncSocket *s); +static int AsyncTCPSocketGetFd(AsyncSocket *asock); +static int AsyncTCPSocketGetRemoteIPStr(AsyncSocket *asock, const char **ipStr); +static int AsyncTCPSocketGetINETIPStr(AsyncSocket *asock, int socketFamily, + char **ipRetStr); +static unsigned int AsyncTCPSocketGetPort(AsyncSocket *asock); +static int AsyncTCPSocketUseNodelay(AsyncSocket *asock, Bool nodelay); +static int AsyncTCPSocketSetTCPTimeouts(AsyncSocket *asock, int keepIdle, + int keepIntvl, int keepCnt); +static Bool AsyncTCPSocketSetBufferSizes(AsyncSocket *asock, + int sendSz, int recvSz); +static void AsyncTCPSocketSetSendLowLatencyMode(AsyncSocket *asock, + Bool enable); +static Bool AsyncTCPSocketConnectSSL(AsyncSocket *asock, + struct _SSLVerifyParam *verifyParam, + void *sslContext); +static void AsyncTCPSocketStartSslConnect(AsyncSocket *asock, + SSLVerifyParam *verifyParam, + void *sslCtx, + AsyncSocketSslConnectFn sslConnectFn, + void *clientData); +static Bool AsyncTCPSocketAcceptSSL(AsyncSocket *asock, void *sslCtx); +static void AsyncTCPSocketStartSslAccept(AsyncSocket *asock, void *sslCtx, + AsyncSocketSslAcceptFn sslAcceptFn, + void *clientData); +static int AsyncTCPSocketFlush(AsyncSocket *asock, int timeoutMS); +static void AsyncTCPSocketCancelRecvCb(AsyncTCPSocket *asock); + +static int AsyncTCPSocketRecv(AsyncSocket *asock, + void *buf, int len, Bool partial, void *cb, void *cbData); +static int AsyncTCPSocketRecvPassedFd(AsyncSocket *asock, void *buf, int len, + void *cb, void *cbData); +static int AsyncTCPSocketGetReceivedFd(AsyncSocket *asock); +static int AsyncTCPSocketSend(AsyncSocket *asock, void *buf, int len, + AsyncSocketSendFn sendFn, void *clientData); +static int AsyncTCPSocketIsSendBufferFull(AsyncSocket *asock); +static int AsyncTCPSocketClose(AsyncSocket *asock); +static int AsyncTCPSocketCancelRecv(AsyncSocket *asock, int *partialRecvd, + void **recvBuf, void **recvFn, + Bool cancelOnSend); +static void AsyncTCPSocketCancelCbForClose(AsyncSocket *asock); +static int AsyncTCPSocketGetLocalVMCIAddress(AsyncSocket *asock, + uint32 *cid, uint32 *port); +static int AsyncTCPSocketGetRemoteVMCIAddress(AsyncSocket *asock, + uint32 *cid, uint32 *port); +static void AsyncTCPSocketSetCloseOptions(AsyncSocket *asock, + int flushEnabledMaxWaitMsec, + AsyncSocketCloseFn closeCb); +static void AsyncTCPSocketDestroy(AsyncSocket *s); +static int AsyncTCPSocketRecvBlocking(AsyncSocket *s, void *buf, int len, + int *received, int timeoutMS); +static int AsyncTCPSocketRecvPartialBlocking(AsyncSocket *s, void *buf, int len, + int *received, int timeoutMS); +static int AsyncTCPSocketSendBlocking(AsyncSocket *s, void *buf, int len, + int *sent, int timeoutMS); +static int AsyncTCPSocketDoOneMsg(AsyncSocket *s, Bool read, int timeoutMS); + + +static const AsyncSocketVTable asyncTCPSocketVTable = { AsyncSocketGetState, - AsyncSocketGetGenericErrno, - AsyncSocketGetFd, - AsyncSocketGetRemoteIPStr, - AsyncSocketGetINETIPStr, - AsyncSocketGetPort, - AsyncSocketUseNodelay, - AsyncSocketSetTCPTimeouts, - AsyncSocketSetBufferSizes, - AsyncSocketSetSendLowLatencyMode, - AsyncSocketConnectSSL, - AsyncSocketStartSslConnect, - AsyncSocketAcceptSSL, - AsyncSocketStartSslAccept, - AsyncSocketFlush, - AsyncSocketRecv, - AsyncSocketRecvPassedFd, - AsyncSocketGetReceivedFd, - AsyncSocketSend, - AsyncSocketIsSendBufferFull, - AsyncSocketClose, - AsyncSocketCancelRecv, - AsyncSocketCancelCbForClose, - AsyncSocketGetLocalVMCIAddress, - AsyncSocketGetRemoteVMCIAddress, - NULL, - NULL, - NULL, - NULL, - AsyncSocketDispatchConnect, - AsyncSocketSendInternal, - AsyncSocketSendSocket, - AsyncSocketRecvSocket, - AsyncSocketIPollSendCallback, - AsyncSocketIPollRecvCallback, - AsyncSocketHasDataPendingSocket, - AsyncSocketCancelListenCbSocket, - AsyncSocketCancelRecvCbSocket, - AsyncSocketCancelCbForCloseSocket, - AsyncSocketCancelCbForConnectingCloseSocket, - AsyncSocketCloseSocket, - NULL, + AsyncTCPSocketGetGenericErrno, + AsyncTCPSocketGetFd, + AsyncTCPSocketGetRemoteIPStr, + AsyncTCPSocketGetINETIPStr, + AsyncTCPSocketGetPort, + AsyncTCPSocketUseNodelay, + AsyncTCPSocketSetTCPTimeouts, + AsyncTCPSocketSetBufferSizes, + AsyncTCPSocketSetSendLowLatencyMode, + AsyncTCPSocketSetCloseOptions, + AsyncTCPSocketConnectSSL, + AsyncTCPSocketStartSslConnect, + AsyncTCPSocketAcceptSSL, + AsyncTCPSocketStartSslAccept, + AsyncTCPSocketFlush, + AsyncTCPSocketRecv, + AsyncTCPSocketRecvPassedFd, + AsyncTCPSocketGetReceivedFd, + AsyncTCPSocketSend, + AsyncTCPSocketIsSendBufferFull, + NULL, /* getNetworkStats */ + AsyncTCPSocketClose, + AsyncTCPSocketCancelRecv, + AsyncTCPSocketCancelCbForClose, + AsyncTCPSocketGetLocalVMCIAddress, + AsyncTCPSocketGetRemoteVMCIAddress, + NULL, /* getWebSocketError */ + NULL, /* getWebSocketURI */ + NULL, /* getWebSocketCookie */ + NULL, /* getWebSocketCloseStatus */ + NULL, /* getWebSocketProtocol */ + AsyncTCPSocketRecvBlocking, + AsyncTCPSocketRecvPartialBlocking, + AsyncTCPSocketSendBlocking, + AsyncTCPSocketDoOneMsg, + AsyncTCPSocketWaitForConnection, + AsyncTCPSocketDestroy }; /* - *---------------------------------------------------------------------------- + *---------------------------------------------------------------------- * - * AsyncSocketLock -- - * AsyncSocketUnlock -- + * BaseSocket -- * - * Acquire/Release the lock provided by the client when creating the - * AsyncSocket object. + * Return a pointer to the tcp socket's base class. * - * Results: - * None. + *---------------------------------------------------------------------- + */ + +static INLINE AsyncSocket * +BaseSocket(AsyncTCPSocket *s) +{ + ASSERT((void *)s == (void *)&s->base); + return &s->base; +} + + +/* + *---------------------------------------------------------------------- * - * Side effects: - * None. + * TCPSocket -- * - *---------------------------------------------------------------------------- + * Cast a generic AsyncSocket pointer to AsyncTCPSocket, after + * asserting this is legal. + * + *---------------------------------------------------------------------- */ -INLINE void -AsyncSocketLock(AsyncSocket *asock) // IN: +static INLINE AsyncTCPSocket * +TCPSocket(AsyncSocket *s) { - if (asock->pollParams.lock) { - MXUser_AcquireRecLock(asock->pollParams.lock); - } + ASSERT(s->vt == &asyncTCPSocketVTable); + ASSERT(s == &((AsyncTCPSocket *)s)->base); + return (AsyncTCPSocket *)s; } -INLINE void -AsyncSocketUnlock(AsyncSocket *asock) // IN: +/* + *---------------------------------------------------------------------- + * + * TCPSocketLock -- + * TCPSocketUnlock -- + * TCPSocketIsLocked -- + * TCPSocketAddRef -- + * TCPSocketRelease -- + * TCPSocketPollParams -- + * TCPSocketGetState -- + * TCPSocketSetState -- + * TCPSocketHandleError -- + * + * AsyncTCPSocket versions of base class interfaces. These + * simply invoke the corresponding function on the base class + * pointer. + * + *---------------------------------------------------------------------- + */ + +static INLINE void +AsyncTCPSocketLock(AsyncTCPSocket *asock) +{ + AsyncSocketLock(BaseSocket(asock)); +} + +static INLINE void +AsyncTCPSocketUnlock(AsyncTCPSocket *asock) { - if (asock->pollParams.lock) { - MXUser_ReleaseRecLock(asock->pollParams.lock); - } + AsyncSocketUnlock(BaseSocket(asock)); +} + +static INLINE Bool +AsyncTCPSocketIsLocked(AsyncTCPSocket *asock) +{ + return AsyncSocketIsLocked(BaseSocket(asock)); +} + +static INLINE void +AsyncTCPSocketAddRef(AsyncTCPSocket *asock) +{ + AsyncSocketAddRef(BaseSocket(asock)); +} + +static INLINE void +AsyncTCPSocketRelease(AsyncTCPSocket *asock) +{ + AsyncSocketRelease(BaseSocket(asock)); +} + +static INLINE AsyncSocketPollParams * +AsyncTCPSocketPollParams(AsyncTCPSocket *asock) +{ + return AsyncSocketGetPollParams(BaseSocket(asock)); +} + +static INLINE Bool +AsyncTCPSocketGetState(AsyncTCPSocket *asock) +{ + return AsyncSocketGetState(BaseSocket(asock)); +} + +static INLINE void +AsyncTCPSocketSetState(AsyncTCPSocket *asock, AsyncSocketState state) +{ + AsyncSocketSetState(BaseSocket(asock), state); +} + +static INLINE void +AsyncTCPSocketHandleError(AsyncTCPSocket *asock, int error) +{ + AsyncSocketHandleError(BaseSocket(asock), error); } /* - *---------------------------------------------------------------------------- - * - * AsyncSocketIsLocked -- + *---------------------------------------------------------------------- * - * If a lock is associated with the socket, check whether the calling - * thread holds the lock. + * TCPSOCKWARN -- + * TCPSOCKLOG -- + * TCPSOCKLG0 -- * - * Results: - * TRUE if calling thread holds the lock, or if there is no assoicated - * lock. + * AsyncTCPSocket versions of base class logging macros. These + * simply invoke the corresponding macro on the base class + * pointer. * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -INLINE Bool -AsyncSocketIsLocked(AsyncSocket *asock) // IN: -{ - if (asock->pollParams.lock && Poll_LockingEnabled()) { - return MXUser_IsCurThreadHoldingRecLock(asock->pollParams.lock); - } - return TRUE; -} +#define TCPSOCKWARN(a,b) ASOCKWARN(BaseSocket(a), b) +#define TCPSOCKLOG(a,b,c) ASOCKLOG(a, BaseSocket(b), c) +#define TCPSOCKLG0(a,b) ASOCKLG0(BaseSocket(a), b) /* *---------------------------------------------------------------------------- * - * AsyncSocket_Init -- + * AsyncTCPSocket_Init -- * * Initializes the host's socket library. NOP on Posix. * On Windows, calls WSAStartup(). @@ -323,7 +550,7 @@ AsyncSocketIsLocked(AsyncSocket *asock) // IN: */ int -AsyncSocket_Init(void) +AsyncTCPSocket_Init(void) { #ifdef _WIN32 WSADATA wsaData; @@ -338,12 +565,13 @@ AsyncSocket_Init(void) /* *---------------------------------------------------------------------------- * - * AsyncSocket_Err2String -- + * AsyncTCPSocketGetFd -- * - * Returns the error string associated with error code. + * Returns the fd for this socket. If listening, return one of + * the asock6/asock4 fds. * * Results: - * Error string. + * File descriptor. * * Side effects: * None. @@ -351,117 +579,29 @@ AsyncSocket_Init(void) *---------------------------------------------------------------------------- */ -const char * -AsyncSocket_Err2String(int err) // IN +static int +AsyncTCPSocketGetFd(AsyncSocket *base) // IN { - return Msg_StripMSGID(AsyncSocket_MsgError(err)); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocket_MsgError -- - * - * Returns the message associated with error code. - * - * Results: - * Message string. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ + AsyncTCPSocket *asock = TCPSocket(base); -const char * -AsyncSocket_MsgError(int asyncSockError) // IN -{ - const char *result = NULL; - switch (asyncSockError) { - case ASOCKERR_SUCCESS: - result = MSGID(asyncsocket.success) "Success"; - break; - case ASOCKERR_GENERIC: - result = MSGID(asyncsocket.generic) "Asyncsocket error"; - break; - case ASOCKERR_INVAL: - result = MSGID(asyncsocket.invalid) "Invalid parameters"; - break; - case ASOCKERR_TIMEOUT: - result = MSGID(asyncsocket.timeout) "Time-out error"; - break; - case ASOCKERR_NOTCONNECTED: - result = MSGID(asyncsocket.notconnected) "Local socket not connected"; - break; - case ASOCKERR_REMOTE_DISCONNECT: - result = MSGID(asyncsocket.remotedisconnect) "Remote disconnected"; - break; - case ASOCKERR_CLOSED: - result = MSGID(asyncsocket.closed) "Closed socket"; - break; - case ASOCKERR_CONNECT: - result = MSGID(asyncsocket.connect) "Connection error"; - break; - case ASOCKERR_POLL: - result = MSGID(asyncsocket.poll) "Poll registration error"; - break; - case ASOCKERR_BIND: - result = MSGID(asyncsocket.bind) "Socket bind error"; - break; - case ASOCKERR_BINDADDRINUSE: - result = MSGID(asyncsocket.bindaddrinuse) "Socket bind address already in use"; - break; - case ASOCKERR_LISTEN: - result = MSGID(asyncsocket.listen) "Socket listen error"; - break; - case ASOCKERR_CONNECTSSL: - result = MSGID(asyncsocket.connectssl) "Connection error: could not negotiate SSL"; - break; - case ASOCKERR_NETUNREACH: - result = MSGID(asyncsocket.netunreach) "Network unreachable"; - break; - case ASOCKERR_ADDRUNRESV: - result = MSGID(asyncsocket.addrunresv) "Address unresolvable"; - break; - } - - if (!result) { - Warning("%s was passed bad code %d\n", __FUNCTION__, asyncSockError); - result = MSGID(asyncsocket.unknown) "Unknown error"; + if (asock->fd != -1) { + return asock->fd; + } else if (asock->listenAsock4 && asock->listenAsock4->fd != -1) { + return asock->listenAsock4->fd; + } else if (asock->listenAsock6 && asock->listenAsock6->fd != -1) { + return asock->listenAsock6->fd; + } else { + return -1; } - return result; -} - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketGetFd -- - * - * Returns the fd for this socket. - * - * Results: - * File descriptor. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -AsyncSocketGetFd(AsyncSocket *s) -{ - return s->fd; } /* *---------------------------------------------------------------------------- * - * AsyncSocketGetAddr -- + * AsyncTCPSocketGetAddr -- * - * Given an AsyncSocket object, return the sockaddr associated with the + * Given an AsyncTCPSocket object, return the sockaddr associated with the * requested address family's file descriptor if available. * * Passing AF_UNSPEC to socketFamily will provide you with the first @@ -479,16 +619,15 @@ AsyncSocketGetFd(AsyncSocket *s) */ static int -AsyncSocketGetAddr(AsyncSocket *asock, // IN - int socketFamily, // IN - struct sockaddr_storage *outAddr, // OUT - socklen_t *outAddrLen) // IN/OUT +AsyncTCPSocketGetAddr(AsyncTCPSocket *asock, // IN + int socketFamily, // IN + struct sockaddr_storage *outAddr, // OUT + socklen_t *outAddrLen) // IN/OUT { - AsyncSocket *tempAsock; + AsyncTCPSocket *tempAsock; int tempFd; struct sockaddr_storage addr; socklen_t addrLen = sizeof addr; - int ret = ASOCKERR_GENERIC; if (asock->fd != -1) { tempAsock = asock; @@ -502,36 +641,32 @@ AsyncSocketGetAddr(AsyncSocket *asock, // IN return ASOCKERR_INVAL; } - AsyncSocketLock(tempAsock); + ASSERT(AsyncTCPSocketIsLocked(tempAsock)); tempFd = tempAsock->fd; if (getsockname(tempFd, (struct sockaddr*)&addr, &addrLen) == 0) { if (socketFamily != AF_UNSPEC && addr.ss_family != socketFamily) { - ret = ASOCKERR_INVAL; - goto outWithLock; + return ASOCKERR_INVAL; } memcpy(outAddr, &addr, Min(*outAddrLen, addrLen)); *outAddrLen = addrLen; - ret = ASOCKERR_SUCCESS; + return ASOCKERR_SUCCESS; } else { - ASOCKWARN(tempAsock, ("%s: could not locate socket.\n", __FUNCTION__)); + TCPSOCKWARN(tempAsock, ("%s: could not locate socket.\n", __FUNCTION__)); + return ASOCKERR_GENERIC; } - - outWithLock: - AsyncSocketUnlock(tempAsock); - return ret; } /* *---------------------------------------------------------------------------- * - * AsyncSocketGetRemoteIPStr -- + * AsyncTCPSocketGetRemoteIPStr -- * - * Given an AsyncSocket object, returns the remote IP address associated - * with it, or an error if the request is meaningless for the underlying - * connection. + * Given an AsyncTCPSocket object, returns the remote IP address + * associated with it, or an error if the request is meaningless + * for the underlying connection. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. @@ -542,18 +677,18 @@ AsyncSocketGetAddr(AsyncSocket *asock, // IN *---------------------------------------------------------------------------- */ -int -AsyncSocketGetRemoteIPStr(AsyncSocket *asock, // IN - const char **ipRetStr) // OUT +static int +AsyncTCPSocketGetRemoteIPStr(AsyncSocket *base, // IN + const char **ipRetStr) // OUT { + AsyncTCPSocket *asock = TCPSocket(base); int ret = ASOCKERR_SUCCESS; ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); ASSERT(ipRetStr != NULL); if (ipRetStr == NULL || asock == NULL || - asock->state != AsyncSocketConnected || + AsyncTCPSocketGetState(asock) != AsyncSocketConnected || (asock->remoteAddrLen != sizeof (struct sockaddr_in) && asock->remoteAddrLen != sizeof (struct sockaddr_in6))) { ret = ASOCKERR_GENERIC; @@ -576,9 +711,9 @@ AsyncSocketGetRemoteIPStr(AsyncSocket *asock, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketGetINETIPStr -- + * AsyncTCPSocketGetINETIPStr -- * - * Given an AsyncSocket object, returns the IP addresses associated with + * Given an AsyncTCPSocket object, returns the IP addresses associated with * the requested address family's file descriptor if available. * * Passing AF_UNSPEC to socketFamily will provide you with the first @@ -597,37 +732,36 @@ AsyncSocketGetRemoteIPStr(AsyncSocket *asock, // IN *---------------------------------------------------------------------------- */ -int -AsyncSocketGetINETIPStr(AsyncSocket *asock, // IN - int socketFamily, // IN - char **ipRetStr) // OUT +static int +AsyncTCPSocketGetINETIPStr(AsyncSocket *base, // IN + int socketFamily, // IN + char **ipRetStr) // OUT { + AsyncTCPSocket *asock = TCPSocket(base); struct sockaddr_storage addr; socklen_t addrLen = sizeof addr; int ret; - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); - ret = AsyncSocketGetAddr(asock, socketFamily, &addr, &addrLen); + ret = AsyncTCPSocketGetAddr(asock, socketFamily, &addr, &addrLen); if (ret == ASOCKERR_SUCCESS) { char addrBuf[NI_MAXHOST]; if (ipRetStr == NULL) { - ASOCKWARN(asock, ("%s: Output string is not usable.\n", - __FUNCTION__)); + TCPSOCKWARN(asock, ("%s: Output string is not usable.\n", + __FUNCTION__)); ret = ASOCKERR_INVAL; } else if (Posix_GetNameInfo((struct sockaddr *)&addr, addrLen, addrBuf, sizeof addrBuf, NULL, 0, NI_NUMERICHOST) == 0) { *ipRetStr = Util_SafeStrdup(addrBuf); } else { - ASOCKWARN(asock, ("%s: could not find IP address.\n", __FUNCTION__)); + TCPSOCKWARN(asock, ("%s: could not find IP address.\n", __FUNCTION__)); ret = ASOCKERR_GENERIC; } } - AsyncSocketUnlock(asock); - return ret; } @@ -635,9 +769,9 @@ AsyncSocketGetINETIPStr(AsyncSocket *asock, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketGetLocalVMCIAddress -- + * AsyncTCPSocketGetLocalVMCIAddress -- * - * Given an AsyncSocket object, returns the local VMCI context ID and + * Given an AsyncTCPSocket object, returns the local VMCI context ID and * port number associated with it, or an error if the request is * meaningless for the underlying connection. * @@ -650,11 +784,12 @@ AsyncSocketGetINETIPStr(AsyncSocket *asock, // IN *---------------------------------------------------------------------------- */ -int -AsyncSocketGetLocalVMCIAddress(AsyncSocket *asock, // IN - uint32 *cid, // OUT: optional - uint32 *port) // OUT: optional +static int +AsyncTCPSocketGetLocalVMCIAddress(AsyncSocket *base, // IN + uint32 *cid, // OUT: optional + uint32 *port) // OUT: optional { + AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); if (asock->localAddrLen != sizeof(struct sockaddr_vm)) { @@ -676,9 +811,9 @@ AsyncSocketGetLocalVMCIAddress(AsyncSocket *asock, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketGetRemoteVMCIAddress -- + * AsyncTCPSocketGetRemoteVMCIAddress -- * - * Given an AsyncSocket object, returns the remote VMCI context ID and + * Given an AsyncTCPSocket object, returns the remote VMCI context ID and * port number associated with it, or an error if the request is * meaningless for the underlying connection. * @@ -691,11 +826,12 @@ AsyncSocketGetLocalVMCIAddress(AsyncSocket *asock, // IN *---------------------------------------------------------------------------- */ -int -AsyncSocketGetRemoteVMCIAddress(AsyncSocket *asock, // IN - uint32 *cid, // OUT: optional - uint32 *port) // OUT: optional +static int +AsyncTCPSocketGetRemoteVMCIAddress(AsyncSocket *base, // IN + uint32 *cid, // OUT: optional + uint32 *port) // OUT: optional { + AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); if (asock->remoteAddrLen != sizeof(struct sockaddr_vm)) { @@ -717,12 +853,12 @@ AsyncSocketGetRemoteVMCIAddress(AsyncSocket *asock, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketListenImpl -- + * AsyncTCPSocketListenImpl -- * * Initializes, binds, and listens on pre-populated address structure. * * Results: - * New AsyncSocket in listening state or NULL on error. + * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket, binds and listens. @@ -730,29 +866,20 @@ AsyncSocketGetRemoteVMCIAddress(AsyncSocket *asock, // IN *---------------------------------------------------------------------------- */ -AsyncSocket * -AsyncSocketListenImpl(struct sockaddr_storage *addr, // IN - socklen_t addrLen, // IN - AsyncSocketConnectFn connectFn, // IN - void *clientData, // IN - AsyncSocketPollParams *pollParams, // IN: optional - Bool isWebSock, // IN - Bool webSockUseSSL, // IN: - const char *protocols[], // IN: optional - void *sslCtx, // IN: optional - int *outError) // OUT: optional +static AsyncTCPSocket * +AsyncTCPSocketListenImpl(struct sockaddr_storage *addr, // IN + socklen_t addrLen, // IN + AsyncSocketConnectFn connectFn, // IN + void *clientData, // IN + AsyncSocketPollParams *pollParams, // IN: optional + int *outError) // OUT: optional { - AsyncSocket *asock = AsyncSocketInit(addr->ss_family, pollParams, outError); + AsyncTCPSocket *asock = AsyncTCPSocketInit(addr->ss_family, pollParams, + outError); if (asock != NULL) { -#ifndef VMX86_TOOLS - if (isWebSock) { - AsyncSocketInitWebSocket(asock, clientData, webSockUseSSL, protocols, sslCtx); - } -#endif - - if (AsyncSocketBind(asock, addr, addrLen, outError) && - AsyncSocketListen(asock, connectFn, clientData, outError)) { + if (AsyncTCPSocketBind(asock, addr, addrLen, outError) && + AsyncTCPSocketListen(asock, connectFn, clientData, outError)) { return asock; } } @@ -764,14 +891,14 @@ AsyncSocketListenImpl(struct sockaddr_storage *addr, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketListenerCreateImpl -- + * AsyncTCPSocketListenerCreateImpl -- * * Listens on specified address and/or port for resolved/requested socket * family and accepts new connections. Fires the connect callback with - * new AsyncSocket object for each connection. + * new AsyncTCPSocket object for each connection. * * Results: - * New AsyncSocket in listening state or NULL on error. + * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket, binds and listens. @@ -779,37 +906,34 @@ AsyncSocketListenImpl(struct sockaddr_storage *addr, // IN *---------------------------------------------------------------------------- */ -AsyncSocket * -AsyncSocketListenerCreateImpl(const char *addrStr, // IN: optional - unsigned int port, // IN: optional - int socketFamily, // IN - AsyncSocketConnectFn connectFn, // IN - void *clientData, // IN - AsyncSocketPollParams *pollParams, // IN - Bool isWebSock, // IN - Bool webSockUseSSL, // IN - const char *protocols[], // IN: optional - void *sslCtx, // IN: optional - int *outError) // OUT: optional +static AsyncTCPSocket * +AsyncTCPSocketListenerCreateImpl( + const char *addrStr, // IN: optional + unsigned int port, // IN: optional + int socketFamily, // IN + AsyncSocketConnectFn connectFn, // IN + void *clientData, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT: optional { - AsyncSocket *asock = NULL; + AsyncTCPSocket *asock = NULL; struct sockaddr_storage addr; socklen_t addrLen; char *ipString = NULL; - int getaddrinfoError = AsyncSocketResolveAddr(addrStr, port, socketFamily, - TRUE, &addr, &addrLen, - &ipString); + int getaddrinfoError = AsyncTCPSocketResolveAddr(addrStr, port, socketFamily, + TRUE, &addr, &addrLen, + &ipString); if (getaddrinfoError == 0) { - asock = AsyncSocketListenImpl(&addr, addrLen, connectFn, clientData, - pollParams, isWebSock, webSockUseSSL, - protocols, sslCtx, outError); + asock = AsyncTCPSocketListenImpl(&addr, addrLen, connectFn, clientData, + pollParams, + outError); if (asock) { - ASOCKLG0(asock, + TCPSOCKLG0(asock, ("Created new %s %s listener for (%s)\n", addr.ss_family == AF_INET ? "IPv4" : "IPv6", - isWebSock ? "web socket" : "socket", ipString)); + "socket", ipString)); } else { Log(ASOCKPREFIX "Could not create %s listener socket, error %d: %s\n", addr.ss_family == AF_INET ? "IPv4" : "IPv6", *outError, @@ -819,7 +943,7 @@ AsyncSocketListenerCreateImpl(const char *addrStr, // IN: optiona } else { Log(ASOCKPREFIX "Could not resolve listener socket address.\n"); if (outError) { - *outError = ASOCKERR_LISTEN; + *outError = ASOCKERR_ADDRUNRESV; } } @@ -830,11 +954,11 @@ AsyncSocketListenerCreateImpl(const char *addrStr, // IN: optiona /* *---------------------------------------------------------------------------- * - * AsyncSocketListenerCreate -- + * AsyncSocket_Listen -- * * Listens on specified address and/or port for all resolved socket * families and accepts new connections. Fires the connect callback with - * new AsyncSocket object for each connection. + * new AsyncTCPSocket object for each connection. * * If address string is present and that string is not the "localhost" * loopback, then we will listen on resolved address only. @@ -857,7 +981,7 @@ AsyncSocketListenerCreateImpl(const char *addrStr, // IN: optiona * If address string is NULL, port cannot be 0. * * Results: - * New AsyncSocket in listening state or NULL on error. + * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket/s, binds and listens. @@ -866,37 +990,37 @@ AsyncSocketListenerCreateImpl(const char *addrStr, // IN: optiona */ AsyncSocket * -AsyncSocketListenerCreate(const char *addrStr, // IN: optional - unsigned int port, // IN: optional - AsyncSocketConnectFn connectFn, // IN - void *clientData, // IN - AsyncSocketPollParams *pollParams, // IN - Bool isWebSock, // IN - Bool webSockUseSSL, // IN - const char *protocols[], // IN: optional - void *sslCtx, // IN: optional - int *outError) // OUT: optional +AsyncSocket_Listen(const char *addrStr, // IN: optional + unsigned int port, // IN: optional + AsyncSocketConnectFn connectFn, // IN + void *clientData, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT: optional { if (addrStr != NULL && *addrStr != '\0' && Str_Strcmp(addrStr, "localhost")) { - return AsyncSocketListenerCreateImpl(addrStr, port, AF_UNSPEC, connectFn, - clientData, pollParams, FALSE, - FALSE, protocols, sslCtx, outError); + AsyncTCPSocket *asock; + + asock = AsyncTCPSocketListenerCreateImpl(addrStr, port, AF_UNSPEC, + connectFn, + clientData, pollParams, + outError); + return BaseSocket(asock); } else { Bool localhost = addrStr != NULL && !Str_Strcmp(addrStr, "localhost"); unsigned int tempPort = port; - AsyncSocket *asock6 = NULL; - AsyncSocket *asock4 = NULL; + AsyncTCPSocket *asock6 = NULL; + AsyncTCPSocket *asock4 = NULL; int tempError4; int tempError6; - asock6 = AsyncSocketListenerCreateImpl(addrStr, port, AF_INET6, - connectFn, clientData, pollParams, - isWebSock, webSockUseSSL, protocols, - sslCtx, &tempError6); + asock6 = AsyncTCPSocketListenerCreateImpl(addrStr, port, AF_INET6, + connectFn, clientData, + pollParams, + &tempError6); if (localhost && port == 0) { - tempPort = AsyncSocket_GetPort(asock6); + tempPort = AsyncSocket_GetPort(BaseSocket(asock6)); if (tempPort == MAX_UINT32) { Log(ASOCKPREFIX "Could not resolve IPv6 listener socket port number.\n"); @@ -904,24 +1028,23 @@ AsyncSocketListenerCreate(const char *addrStr, // IN: optional } } - asock4 = AsyncSocketListenerCreateImpl(addrStr, tempPort, AF_INET, - connectFn, clientData, pollParams, - isWebSock, webSockUseSSL, - protocols, sslCtx, &tempError4); + asock4 = AsyncTCPSocketListenerCreateImpl(addrStr, tempPort, AF_INET, + connectFn, clientData, + pollParams, + &tempError4); if (localhost && port == 0 && tempError4 == ASOCKERR_BINDADDRINUSE) { Log(ASOCKPREFIX "Failed to reuse IPv6 localhost port number for IPv4 " "listener socket.\n"); - AsyncSocket_Close(asock6); + AsyncSocket_Close(BaseSocket(asock6)); tempError4 = ASOCKERR_SUCCESS; - asock4 = AsyncSocketListenerCreateImpl(addrStr, port, AF_INET, - connectFn, clientData, - pollParams, isWebSock, - webSockUseSSL, protocols, - sslCtx, &tempError4); + asock4 = AsyncTCPSocketListenerCreateImpl(addrStr, port, AF_INET, + connectFn, clientData, + pollParams, + &tempError4); - tempPort = AsyncSocket_GetPort(asock4); + tempPort = AsyncSocket_GetPort(BaseSocket(asock4)); if (tempPort == MAX_UINT32) { Log(ASOCKPREFIX "Could not resolve IPv4 listener socket port number.\n"); @@ -929,39 +1052,31 @@ AsyncSocketListenerCreate(const char *addrStr, // IN: optional } tempError6 = ASOCKERR_SUCCESS; - asock6 = AsyncSocketListenerCreateImpl(addrStr, tempPort, AF_INET6, - connectFn, clientData, - pollParams, isWebSock, - webSockUseSSL, protocols, - sslCtx, &tempError6); + asock6 = AsyncTCPSocketListenerCreateImpl(addrStr, tempPort, AF_INET6, + connectFn, clientData, + pollParams, + &tempError6); if (!asock6 && tempError6 == ASOCKERR_BINDADDRINUSE) { Log(ASOCKPREFIX "Failed to reuse IPv4 localhost port number for " "IPv6 listener socket.\n"); - AsyncSocket_Close(asock4); + AsyncSocket_Close(BaseSocket(asock4)); } } if (asock6 && asock4) { - AsyncSocket *asock; + AsyncTCPSocket *asock; - asock = AsyncSocketCreate(NULL); - asock->state = AsyncSocketListening; - asock->asockType = ASYNCSOCKET_TYPE_SOCKET; + asock = AsyncTCPSocketCreate(pollParams); + AsyncTCPSocketSetState(asock, AsyncSocketListening); asock->listenAsock6 = asock6; asock->listenAsock4 = asock4; - if (asock->pollParams.iPoll == NULL) { - asock->vt = &asyncStreamSocketVTable; - } else { - asock->vt = &asyncStreamSocketIPollVTable; - } - - return asock; + return BaseSocket(asock); } else if (asock6) { - return asock6; + return BaseSocket(asock6); } else if (asock4) { - return asock4; + return BaseSocket(asock4); } if (outError) { @@ -983,14 +1098,14 @@ AsyncSocketListenerCreate(const char *addrStr, // IN: optional /* *---------------------------------------------------------------------------- * - * AsyncSocketListenerCreateLoopback -- + * AsyncTCPSocketListenerCreateLoopback -- * * Listens on loopback interface and port for all resolved socket * families and accepts new connections. Fires the connect callback with - * new AsyncSocket object for each connection. + * new AsyncTCPSocket object for each connection. * * Results: - * New AsyncSocket in listening state or NULL on error. + * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket/s, binds and listens. @@ -998,17 +1113,15 @@ AsyncSocketListenerCreate(const char *addrStr, // IN: optional *---------------------------------------------------------------------------- */ -static AsyncSocket * -AsyncSocketListenerCreateLoopback(unsigned int port, // IN - AsyncSocketConnectFn connectFn, // IN - void *clientData, // IN - AsyncSocketPollParams *pollParams, // IN - Bool isWebSock, // IN - Bool webSockUseSSL, // IN - int *outError) // OUT: optional +AsyncSocket * +AsyncSocket_ListenLoopback(unsigned int port, // IN + AsyncSocketConnectFn connectFn, // IN + void *clientData, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT: optional { - AsyncSocket *asock6 = NULL; - AsyncSocket *asock4 = NULL; + AsyncTCPSocket *asock6 = NULL; + AsyncTCPSocket *asock4 = NULL; int tempError4; int tempError6; @@ -1017,36 +1130,27 @@ AsyncSocketListenerCreateLoopback(unsigned int port, // IN * not work for IPv6 on old Linux versions like 2.6.18. So, * using IP address for both the cases to be consistent. */ - asock6 = AsyncSocketListenerCreateImpl("::1", port, AF_INET6, - connectFn, clientData, pollParams, - isWebSock, webSockUseSSL, - NULL, NULL, &tempError6); + asock6 = AsyncTCPSocketListenerCreateImpl("::1", port, AF_INET6, + connectFn, clientData, pollParams, + &tempError6); - asock4 = AsyncSocketListenerCreateImpl("127.0.0.1", port, AF_INET, - connectFn, clientData, pollParams, - isWebSock, webSockUseSSL, - NULL, NULL, &tempError4); + asock4 = AsyncTCPSocketListenerCreateImpl("127.0.0.1", port, AF_INET, + connectFn, clientData, pollParams, + &tempError4); if (asock6 && asock4) { - AsyncSocket *asock; + AsyncTCPSocket *asock; - asock = AsyncSocketCreate(NULL); - asock->state = AsyncSocketListening; - asock->asockType = ASYNCSOCKET_TYPE_SOCKET; + asock = AsyncTCPSocketCreate(pollParams); + AsyncTCPSocketSetState(asock, AsyncSocketListening); asock->listenAsock6 = asock6; asock->listenAsock4 = asock4; - if (asock->pollParams.iPoll == NULL) { - asock->vt = &asyncStreamSocketVTable; - } else { - asock->vt = &asyncStreamSocketIPollVTable; - } - - return asock; + return BaseSocket(asock); } else if (asock6) { - return asock6; + return BaseSocket(asock6); } else if (asock4) { - return asock4; + return BaseSocket(asock4); } if (outError) { @@ -1067,95 +1171,13 @@ AsyncSocketListenerCreateLoopback(unsigned int port, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocket_Listen -- - * - * Listens on specified address and/or port for all resolved socket - * families and accepts new connections. Fires the connect callback with - * new AsyncSocket object for each connection. - * - * If address string is present and that string is not the "localhost" - * loopback, then we will listen on resolved address only. - * - * If address string is NULL or is "localhost" we will listen on all - * address families that will resolve on the host. - * - * If port requested is 0, we will let the system assign the first - * available port. - * - * If address string is NULL and port requested is not 0, we will listen - * on any address for all resolved protocols for the port requested. - * - * If address string is "localhost" and port is 0, we will use the first - * port we are given if the host supports multiple address families. - * If by chance we try to bind on a port that is available for one - * protocol and not the other, we will attempt a second time with the - * order of address families reversed. - * - * If address string is NULL, port cannot be 0. - * - * Results: - * New AsyncSocket in listening state or NULL on error. - * - * Side effects: - * Creates new socket/s, binds and listens. - * - *---------------------------------------------------------------------------- - */ - -AsyncSocket * -AsyncSocket_Listen(const char *addrStr, // IN: optional - unsigned int port, // IN: optional - AsyncSocketConnectFn connectFn, // IN - void *clientData, // IN - AsyncSocketPollParams *pollParams, // IN - int *outError) // OUT: optional -{ - return AsyncSocketListenerCreate(addrStr, port, connectFn, clientData, - pollParams, FALSE, FALSE, NULL, NULL, - outError); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocket_ListenLoopback -- - * - * Listens on loopback interface and port for all resolved socket - * families and accepts new connections. Fires the connect callback with - * new AsyncSocket object for each connection. - * - * Results: - * New AsyncSocket in listening state or NULL on error. - * - * Side effects: - * Creates new socket/s, binds and listens. - * - *---------------------------------------------------------------------------- - */ - -AsyncSocket * -AsyncSocket_ListenLoopback(unsigned int port, // IN - AsyncSocketConnectFn connectFn, // IN - void *clientData, // IN - AsyncSocketPollParams *pollParams, // IN - int *outError) // OUT: optional -{ - return AsyncSocketListenerCreateLoopback(port, connectFn, clientData, - pollParams, FALSE, FALSE, outError); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocket_ListenVMCI -- + * AsyncTCPSocket_ListenVMCI -- * * Listens on the specified port and accepts new connections. Fires the - * connect callback with new AsyncSocket object for each connection. + * connect callback with new AsyncTCPSocket object for each connection. * * Results: - * New AsyncSocket in listening state or NULL on error. + * New AsyncTCPSocket in listening state or NULL on error. * * Side effects: * Creates new socket, binds and listens. @@ -1172,7 +1194,7 @@ AsyncSocket_ListenVMCI(unsigned int cid, // IN int *outError) // OUT { struct sockaddr_vm addr; - AsyncSocket *asock; + AsyncTCPSocket *asock; int vsockDev = -1; memset(&addr, 0, sizeof addr); @@ -1180,24 +1202,25 @@ AsyncSocket_ListenVMCI(unsigned int cid, // IN addr.svm_cid = cid; addr.svm_port = port; - asock = AsyncSocketListenImpl((struct sockaddr_storage *)&addr, sizeof addr, - connectFn, clientData, pollParams, FALSE, - FALSE, NULL, NULL, outError); + asock = AsyncTCPSocketListenImpl((struct sockaddr_storage *)&addr, + sizeof addr, + connectFn, clientData, pollParams, + outError); VMCISock_ReleaseAFValueFd(vsockDev); - return asock; + return BaseSocket(asock); } /* *---------------------------------------------------------------------------- * - * AsyncSocketInit -- + * AsyncTCPSocketInit -- * * This is an internal routine that sets up a SOCK_STREAM (TCP) socket. * * Results: - * New AsyncSocket or NULL on error. + * New AsyncTCPSocket or NULL on error. * * Side effects: * Creates new socket. @@ -1205,12 +1228,12 @@ AsyncSocket_ListenVMCI(unsigned int cid, // IN *---------------------------------------------------------------------------- */ -AsyncSocket * -AsyncSocketInit(int socketFamily, // IN - AsyncSocketPollParams *pollParams, // IN - int *outError) // OUT +static AsyncTCPSocket * +AsyncTCPSocketInit(int socketFamily, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT { - AsyncSocket *asock = NULL; + AsyncTCPSocket *asock = NULL; int error = ASOCKERR_GENERIC; int sysErr; int fd; @@ -1230,7 +1253,7 @@ AsyncSocketInit(int socketFamily, // IN * Wrap it with an asock object */ - if ((asock = AsyncSocket_AttachToFd(fd, pollParams, &error)) == NULL) { + if ((asock = AsyncTCPSocketAttachToFd(fd, pollParams, &error)) == NULL) { goto error; } @@ -1251,7 +1274,7 @@ errorNoFd: /* *---------------------------------------------------------------------------- * - * AsyncSocketGetPortFromAddr -- + * AsyncTCPSocketGetPortFromAddr -- * * This is an internal routine that gets a port given an address. The * address must be in either AF_INET, AF_INET6 or AF_VMCI format. @@ -1266,7 +1289,7 @@ errorNoFd: */ static unsigned int -AsyncSocketGetPortFromAddr(struct sockaddr_storage *addr) +AsyncTCPSocketGetPortFromAddr(struct sockaddr_storage *addr) // IN { ASSERT(NULL != addr); @@ -1294,9 +1317,9 @@ AsyncSocketGetPortFromAddr(struct sockaddr_storage *addr) /* *---------------------------------------------------------------------------- * - * AsyncSocketGetPort -- + * AsyncTCPSocketGetPort -- * - * Given an AsyncSocket object, returns the port number associated with + * Given an AsyncTCPSocket object, returns the port number associated with * the requested address family's file descriptor if available. * * Results: @@ -1308,10 +1331,11 @@ AsyncSocketGetPortFromAddr(struct sockaddr_storage *addr) *---------------------------------------------------------------------------- */ -unsigned int -AsyncSocketGetPort(AsyncSocket *asock) // IN +static unsigned int +AsyncTCPSocketGetPort(AsyncSocket *base) // IN { - AsyncSocket *tempAsock; + AsyncTCPSocket *asock = TCPSocket(base); + AsyncTCPSocket *tempAsock; struct sockaddr_storage addr; socklen_t addrLen = sizeof addr; unsigned int ret = MAX_UINT32; @@ -1326,14 +1350,16 @@ AsyncSocketGetPort(AsyncSocket *asock) // IN return ret; } - AsyncSocketLock(tempAsock); + ASSERT(AsyncTCPSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketIsLocked(tempAsock)); - if (AsyncSocketGetAddr(tempAsock, AF_UNSPEC, &addr, &addrLen) == + if (AsyncTCPSocketGetAddr(tempAsock, AF_UNSPEC, &addr, &addrLen) == ASOCKERR_SUCCESS) { - ret = AsyncSocketGetPortFromAddr(&addr); + return AsyncTCPSocketGetPortFromAddr(&addr); + } else { + return MAX_UINT32; } - AsyncSocketUnlock(tempAsock); return ret; } @@ -1342,7 +1368,7 @@ AsyncSocketGetPort(AsyncSocket *asock) // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketOSVersionSupportsV4Mapped -- + * AsyncTCPSocketOSVersionSupportsV4Mapped -- * * Determine if runtime environment supports IPv4-mapped IPv6 addressed * and all the functionality needed to deal with this scenario. @@ -1357,7 +1383,7 @@ AsyncSocketGetPort(AsyncSocket *asock) // IN */ static Bool -AsyncSocketOSVersionSupportsV4Mapped() +AsyncTCPSocketOSVersionSupportsV4Mapped(void) { #if defined(_WIN32) && !defined(VM_WIN_UWP) OSVERSIONINFOW osvi = {sizeof(OSVERSIONINFOW)}; @@ -1381,7 +1407,7 @@ AsyncSocketOSVersionSupportsV4Mapped() /* *---------------------------------------------------------------------------- * - * AsyncSocketBind -- + * AsyncTCPSocketBind -- * * This is an internal routine that binds a socket to a port. * @@ -1394,11 +1420,11 @@ AsyncSocketOSVersionSupportsV4Mapped() *---------------------------------------------------------------------------- */ -Bool -AsyncSocketBind(AsyncSocket *asock, // IN - struct sockaddr_storage *addr, // IN - socklen_t addrLen, // IN - int *outError) // OUT +static Bool +AsyncTCPSocketBind(AsyncTCPSocket *asock, // IN + struct sockaddr_storage *addr, // IN + socklen_t addrLen, // IN + int *outError) // OUT { int error = ASOCKERR_BIND; int sysErr; @@ -1408,8 +1434,8 @@ AsyncSocketBind(AsyncSocket *asock, // IN ASSERT(NULL != asock->sslSock); ASSERT(NULL != addr); - port = AsyncSocketGetPortFromAddr(addr); - ASOCKLG0(asock, ("creating new listening socket on port %d\n", port)); + port = AsyncTCPSocketGetPortFromAddr(addr); + TCPSOCKLG0(asock, ("creating new listening socket on port %d\n", port)); #ifndef _WIN32 /* @@ -1460,11 +1486,11 @@ AsyncSocketBind(AsyncSocket *asock, // IN * systems that have IPV6_V6ONLY define. There is no good solution for the * case where we cannot enable IPV6_V6ONLY, if we error in this case and do * not have a IPv4 option then we render the application useless. - * See AsyncSocketAcceptInternal for the IN6_IS_ADDR_V4MAPPED validation + * See AsyncTCPSocketAcceptInternal for the IN6_IS_ADDR_V4MAPPED validation * for incomming addresses to close this loophole. */ - if (addr->ss_family == AF_INET6 && AsyncSocketOSVersionSupportsV4Mapped()) { + if (addr->ss_family == AF_INET6 && AsyncTCPSocketOSVersionSupportsV4Mapped()) { int on = 1; if (setsockopt(asock->fd, IPPROTO_IPV6, IPV6_V6ONLY, @@ -1507,7 +1533,7 @@ error: /* *---------------------------------------------------------------------------- * - * AsyncSocketListen -- + * AsyncTCPSocketListen -- * * This is an internal routine that calls listen() on a socket. * @@ -1520,11 +1546,11 @@ error: *---------------------------------------------------------------------------- */ -Bool -AsyncSocketListen(AsyncSocket *asock, // IN - AsyncSocketConnectFn connectFn, // IN - void *clientData, // IN - int *outError) // OUT +static Bool +AsyncTCPSocketListen(AsyncTCPSocket *asock, // IN + AsyncSocketConnectFn connectFn, // IN + void *clientData, // IN + int *outError) // OUT { VMwareStatus pollStatus; int error; @@ -1555,22 +1581,23 @@ AsyncSocketListen(AsyncSocket *asock, // IN * is ready for accept. */ - AsyncSocketLock(asock); - pollStatus = AsyncSocketPollAdd(asock, TRUE, + AsyncTCPSocketLock(asock); + pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_READ | POLL_FLAG_PERIODIC, - AsyncSocketAcceptCallback); + AsyncTCPSocketAcceptCallback); if (pollStatus != VMWARE_STATUS_SUCCESS) { - ASOCKWARN(asock, ("could not register accept callback!\n")); + TCPSOCKWARN(asock, + ("could not register accept callback!\n")); error = ASOCKERR_POLL; - AsyncSocketUnlock(asock); + AsyncTCPSocketUnlock(asock); goto error; } - asock->state = AsyncSocketListening; + AsyncTCPSocketSetState(asock, AsyncSocketListening); asock->connectFn = connectFn; asock->clientData = clientData; - AsyncSocketUnlock(asock); + AsyncTCPSocketUnlock(asock); return TRUE; @@ -1589,36 +1616,36 @@ error: /* *---------------------------------------------------------------------------- * - * AsyncSocketConnectImpl -- + * AsyncTCPSocketConnectImpl -- * - * AsyncSocket AF_INET/AF_INET6 connect. + * AsyncTCPSocket AF_INET/AF_INET6 connect. * * NOTE: This function can block. * * Results: - * AsyncSocket * on success and NULL on failure. + * AsyncTCPSocket * on success and NULL on failure. * On failure, error is returned in *outError. * * Side effects: - * Allocates an AsyncSocket, registers a poll callback. + * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ -static AsyncSocket * -AsyncSocketConnectImpl(int socketFamily, - const char *hostname, - unsigned int port, - AsyncSocketConnectFn connectFn, - void *clientData, - AsyncSocketConnectFlags flags, - AsyncSocketPollParams *pollParams, - int *outError) +static AsyncTCPSocket * +AsyncTCPSocketConnectImpl(int socketFamily, // IN + const char *hostname, // IN + unsigned int port, // IN + AsyncSocketConnectFn connectFn, // IN + void *clientData, // IN + AsyncSocketConnectFlags flags, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT: optional { struct sockaddr_storage addr; int getaddrinfoError; int error; - AsyncSocket *asock; + AsyncTCPSocket *asock; char *ipString = NULL; socklen_t addrLen; @@ -1626,12 +1653,13 @@ AsyncSocketConnectImpl(int socketFamily, * Resolve the hostname. Handles dotted decimal strings, too. */ - getaddrinfoError = AsyncSocketResolveAddr(hostname, port, socketFamily, - FALSE, &addr, &addrLen, &ipString); + getaddrinfoError = AsyncTCPSocketResolveAddr(hostname, port, socketFamily, + FALSE, &addr, &addrLen, + &ipString); if (0 != getaddrinfoError) { Log(ASOCKPREFIX "Failed to resolve %s address '%s' and port %u\n", socketFamily == AF_INET ? "IPv4" : "IPv6", hostname, port); - error = ASOCKERR_CONNECT; + error = ASOCKERR_ADDRUNRESV; goto error; } @@ -1639,12 +1667,12 @@ AsyncSocketConnectImpl(int socketFamily, socketFamily == AF_INET ? "IPv4" : "IPv6", ipString, hostname); free(ipString); - asock = AsyncSocketConnect(&addr, addrLen, connectFn, clientData, - flags, pollParams, &error); + asock = AsyncTCPSocketConnect(&addr, addrLen, connectFn, clientData, + flags, pollParams, &error); if (!asock) { - Warning(ASOCKPREFIX "%s connection attempt failed\n", - socketFamily == AF_INET ? "IPv4" : "IPv6"); - error = ASOCKERR_CONNECT; + Warning(ASOCKPREFIX "%s connection attempt failed: %s\n", + socketFamily == AF_INET ? "IPv4" : "IPv6", + AsyncSocket_MsgError(error)); goto error; } @@ -1662,34 +1690,34 @@ error: /* *---------------------------------------------------------------------------- * - * AsyncSocket_Connect -- + * AsyncTCPSocket_Connect -- * - * AsyncSocket connect. Connection is attempted with AF_INET socket + * AsyncTCPSocket connect. Connection is attempted with AF_INET socket * family, when that fails AF_INET6 is attempted. * * NOTE: This function can block. * * Results: - * AsyncSocket * on success and NULL on failure. + * AsyncTCPSocket * on success and NULL on failure. * On failure, error is returned in *outError. * * Side effects: - * Allocates an AsyncSocket, registers a poll callback. + * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ AsyncSocket * -AsyncSocket_Connect(const char *hostname, - unsigned int port, - AsyncSocketConnectFn connectFn, - void *clientData, - AsyncSocketConnectFlags flags, - AsyncSocketPollParams *pollParams, - int *outError) +AsyncSocket_Connect(const char *hostname, // IN + unsigned int port, // IN + AsyncSocketConnectFn connectFn, // IN + void *clientData, // IN + AsyncSocketConnectFlags flags, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT: optional { int error = ASOCKERR_CONNECT; - AsyncSocket *asock = NULL; + AsyncTCPSocket *asock = NULL; if (!connectFn || !hostname) { error = ASOCKERR_INVAL; @@ -1697,10 +1725,10 @@ AsyncSocket_Connect(const char *hostname, goto error; } - asock = AsyncSocketConnectImpl(AF_INET, hostname, port, connectFn, + asock = AsyncTCPSocketConnectImpl(AF_INET, hostname, port, connectFn, clientData, flags, pollParams, &error); if (!asock) { - asock = AsyncSocketConnectImpl(AF_INET6, hostname, port, connectFn, + asock = AsyncTCPSocketConnectImpl(AF_INET6, hostname, port, connectFn, clientData, flags, pollParams, &error); } @@ -1709,16 +1737,16 @@ error: *outError = error; } - return asock; + return BaseSocket(asock); } /* *---------------------------------------------------------------------------- * - * AsyncSocket_ConnectVMCI -- + * AsyncTCPSocket_ConnectVMCI -- * - * AsyncSocket AF_VMCI constructor. Connects to the specified cid:port, + * AsyncTCPSocket AF_VMCI constructor. Connects to the specified cid:port, * and passes the caller a valid asock via the callback once the * connection has been established. * @@ -1726,7 +1754,7 @@ error: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: - * Allocates an AsyncSocket, registers a poll callback. + * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ @@ -1738,11 +1766,11 @@ AsyncSocket_ConnectVMCI(unsigned int cid, // IN void *clientData, // IN AsyncSocketConnectFlags flags, // IN AsyncSocketPollParams *pollParams, // IN - int *outError) // OUT + int *outError) // OUT: optional { int vsockDev = -1; struct sockaddr_vm addr; - AsyncSocket *asock; + AsyncTCPSocket *asock; memset(&addr, 0, sizeof addr); addr.svm_family = VMCISock_GetAFValueFd(&vsockDev); @@ -1751,12 +1779,12 @@ AsyncSocket_ConnectVMCI(unsigned int cid, // IN Log(ASOCKPREFIX "creating new socket, connecting to %u:%u\n", cid, port); - asock = AsyncSocketConnect((struct sockaddr_storage *)&addr, - sizeof addr, connectFn, clientData, - flags, pollParams, outError); + asock = AsyncTCPSocketConnect((struct sockaddr_storage *)&addr, + sizeof addr, connectFn, clientData, + flags, pollParams, outError); VMCISock_ReleaseAFValueFd(vsockDev); - return asock; + return BaseSocket(asock); } @@ -1766,7 +1794,7 @@ AsyncSocket_ConnectVMCI(unsigned int cid, // IN * * AsyncSocket_ConnectUnixDomain -- * - * AsyncSocket AF_UNIX constructor. Connects to the specified unix socket, + * AsyncTCPSocket AF_UNIX constructor. Connects to the specified unix socket, * and passes the caller a valid asock via the callback once the * connection has been established. * @@ -1774,7 +1802,7 @@ AsyncSocket_ConnectVMCI(unsigned int cid, // IN * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: - * Allocates an AsyncSocket, registers a poll callback. + * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ @@ -1788,7 +1816,7 @@ AsyncSocket_ConnectUnixDomain(const char *path, // IN int *outError) // OUT { struct sockaddr_un addr; - AsyncSocket *asock; + AsyncTCPSocket *asock; memset(&addr, 0, sizeof addr); addr.sun_family = AF_UNIX; @@ -1801,11 +1829,11 @@ AsyncSocket_ConnectUnixDomain(const char *path, // IN Log(ASOCKPREFIX "creating new socket, connecting to %s\n", path); - asock = AsyncSocketConnect((struct sockaddr_storage *)&addr, + asock = AsyncTCPSocketConnect((struct sockaddr_storage *)&addr, sizeof addr, connectFn, clientData, flags, pollParams, outError); - return asock; + return BaseSocket(asock); } #endif @@ -1813,7 +1841,7 @@ AsyncSocket_ConnectUnixDomain(const char *path, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketConnectErrorCheck -- + * AsyncTCPSocketConnectErrorCheck -- * * Check for error on a connecting socket and fire the connect callback * is any error is found. This is only used on Windows. @@ -1828,15 +1856,15 @@ AsyncSocket_ConnectUnixDomain(const char *path, // IN */ static void -AsyncSocketConnectErrorCheck(void *data) // IN: AsyncSocket * +AsyncTCPSocketConnectErrorCheck(void *data) // IN: AsyncTCPSocket * { - AsyncSocket *asock = data; + AsyncTCPSocket *asock = data; Bool removed; PollerFunction func = NULL; - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketIsLocked(asock)); - if (asock->state == AsyncSocketConnecting) { + if (AsyncTCPSocketGetState(asock) == AsyncSocketConnecting) { int sockErr = 0; int sockErrLen = sizeof sockErr; @@ -1850,18 +1878,18 @@ AsyncSocketConnectErrorCheck(void *data) // IN: AsyncSocket * } else { asock->genericErrno = ASOCK_LASTERROR(); } - ASOCKLG0(asock, ("Connection failed: %s\n", + TCPSOCKLG0(asock, ("Connection failed: %s\n", Err_Errno2String(asock->genericErrno))); /* Remove connect callback. */ - removed = AsyncSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, + removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, asock->internalConnectFn); ASSERT(removed); func = asock->internalConnectFn; } /* Remove this callback. */ - removed = AsyncSocketPollRemove(asock, FALSE, POLL_FLAG_PERIODIC, - AsyncSocketConnectErrorCheck); + removed = AsyncTCPSocketPollRemove(asock, FALSE, POLL_FLAG_PERIODIC, + AsyncTCPSocketConnectErrorCheck); ASSERT(removed); asock->internalConnectFn = NULL; @@ -1874,31 +1902,31 @@ AsyncSocketConnectErrorCheck(void *data) // IN: AsyncSocket * /* *---------------------------------------------------------------------------- * - * AsyncSocketConnect -- - * AsyncSocketConnectWithAsock -- + * AsyncTCPSocketConnect -- * - * Internal AsyncSocket constructor. + * Internal AsyncTCPSocket constructor. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_GENERIC. * * Side effects: - * Allocates an AsyncSocket, registers a poll callback. + * Allocates an AsyncTCPSocket, registers a poll callback. * *---------------------------------------------------------------------------- */ -static AsyncSocket * -AsyncSocketConnect(struct sockaddr_storage *addr, - socklen_t addrLen, - AsyncSocketConnectFn connectFn, - void *clientData, - AsyncSocketConnectFlags flags, - AsyncSocketPollParams *pollParams, - int *outError) +static AsyncTCPSocket * +AsyncTCPSocketConnect(struct sockaddr_storage *addr, // IN + socklen_t addrLen, // IN + AsyncSocketConnectFn connectFn, // IN + void *clientData, // IN + AsyncSocketConnectFlags flags, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT { int fd; - AsyncSocket *asock = NULL; + VMwareStatus pollStatus; + AsyncTCPSocket *asock = NULL; int error = ASOCKERR_GENERIC; int sysErr; @@ -1925,38 +1953,11 @@ AsyncSocketConnect(struct sockaddr_storage *addr, * Wrap it with an asock */ - if ((asock = AsyncSocket_AttachToFd(fd, pollParams, &error)) == NULL) { + if ((asock = AsyncTCPSocketAttachToFd(fd, pollParams, &error)) == NULL) { SSLGeneric_close(fd); goto error; } - return AsyncSocketConnectWithAsock(asock, addr, addrLen, connectFn, - clientData, AsyncSocketConnectCallback, - pollParams, outError); - -error: - if (outError) { - *outError = error; - } - - return NULL; -} - -AsyncSocket * -AsyncSocketConnectWithAsock(AsyncSocket *asock, - struct sockaddr_storage *addr, - socklen_t addrLen, - AsyncSocketConnectFn connectFn, - void *clientData, - PollerFunction internalConnectFn, - AsyncSocketPollParams *pollParams, - int *outError) -{ - VMwareStatus pollStatus; - int sysErr; - int error = ASOCKERR_GENERIC; - - ASSERT(internalConnectFn != NULL); /* * Call connect(), which can either succeed immediately or return an error @@ -1968,28 +1969,29 @@ AsyncSocketConnectWithAsock(AsyncSocket *asock, * as a one-time (RTime) callback instead. */ - AsyncSocketLock(asock); + AsyncTCPSocketLock(asock); if (connect(asock->fd, (struct sockaddr *)addr, addrLen) != 0) { if (ASOCK_LASTERROR() == ASOCK_ECONNECTING) { ASSERT(!(vmx86_server && addr->ss_family == AF_UNIX)); - ASOCKLOG(1, asock, ("registering write callback for socket connect\n")); - pollStatus = AsyncSocketPollAdd(asock, TRUE, POLL_FLAG_WRITE, - internalConnectFn); + TCPSOCKLOG(1, asock, + ("registering write callback for socket connect\n")); + pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_WRITE, + AsyncTCPSocketConnectCallback); if (vmx86_win32 && pollStatus == VMWARE_STATUS_SUCCESS && - asock->pollParams.iPoll == NULL) { + AsyncTCPSocketPollParams(asock)->iPoll == NULL) { /* * Work around WSAPoll's bug of not reporting failed connection * by periodically (500 ms) checking for error. */ - pollStatus = AsyncSocketPollAdd(asock, FALSE, POLL_FLAG_PERIODIC, - AsyncSocketConnectErrorCheck, - 500 * 1000); + pollStatus = AsyncTCPSocketPollAdd(asock, FALSE, POLL_FLAG_PERIODIC, + AsyncTCPSocketConnectErrorCheck, + 500 * 1000); if (pollStatus == VMWARE_STATUS_SUCCESS) { - asock->internalConnectFn = internalConnectFn; + asock->internalConnectFn = AsyncTCPSocketConnectCallback; } else { - ASOCKLG0(asock, ("failed to register periodic error check\n")); - AsyncSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, - internalConnectFn); + TCPSOCKLG0(asock, ("failed to register periodic error check\n")); + AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, + AsyncTCPSocketConnectCallback); } } } else { @@ -2006,19 +2008,19 @@ AsyncSocketConnectWithAsock(AsyncSocket *asock, goto errorHaveAsock; } } else { - ASOCKLOG(2, asock, + TCPSOCKLOG(2, asock, ("socket connected, registering RTime callback for connect\n")); - pollStatus = AsyncSocketPollAdd(asock, FALSE, 0, - internalConnectFn, 0); + pollStatus = AsyncTCPSocketPollAdd(asock, FALSE, 0, + AsyncTCPSocketConnectCallback, 0); } if (pollStatus != VMWARE_STATUS_SUCCESS) { - ASOCKWARN(asock, ("failed to register callback in connect!\n")); + TCPSOCKWARN(asock, ("failed to register callback in connect!\n")); error = ASOCKERR_POLL; goto errorHaveAsock; } - asock->state = AsyncSocketConnecting; + AsyncTCPSocketSetState(asock, AsyncSocketConnecting); asock->connectFn = connectFn; asock->clientData = clientData; @@ -2026,15 +2028,16 @@ AsyncSocketConnectWithAsock(AsyncSocket *asock, asock->remoteAddr = *addr; asock->remoteAddrLen = addrLen; - AsyncSocketUnlock(asock); + AsyncTCPSocketUnlock(asock); return asock; errorHaveAsock: SSL_Shutdown(asock->sslSock); - AsyncSocketUnlock(asock); + AsyncTCPSocketUnlock(asock); free(asock); +error: if (outError) { *outError = error; } @@ -2046,9 +2049,10 @@ errorHaveAsock: /* *---------------------------------------------------------------------------- * - * AsyncSocketCreate -- + * AsyncTCPSocketCreate -- * - * AsyncSocket constructor for fields common to all AsyncSocket types. + * AsyncSocket constructor for fields common to all TCP-based + * AsyncSocket types. * * Results: * New AsyncSocket object. @@ -2059,28 +2063,27 @@ errorHaveAsock: *---------------------------------------------------------------------------- */ -AsyncSocket * -AsyncSocketCreate(AsyncSocketPollParams *pollParams) // IN +static AsyncTCPSocket * +AsyncTCPSocketCreate(AsyncSocketPollParams *pollParams) // IN { - AsyncSocket *s; + AsyncTCPSocket *s; s = Util_SafeCalloc(1, sizeof *s); - s->id = Atomic_ReadInc32(&nextid); - s->state = AsyncSocketConnected; + + AsyncSocketInitSocket(BaseSocket(s), pollParams, &asyncTCPSocketVTable); + s->fd = -1; - s->refCount = 1; s->inRecvLoop = FALSE; s->sendBufFull = FALSE; s->sendBufTail = &(s->sendBufList); s->passFd.fd = -1; - if (pollParams) { - s->pollParams = *pollParams; + if (pollParams && pollParams->iPoll) { + s->internalSendFn = AsyncTCPSocketIPollSendCallback; + s->internalRecvFn = AsyncTCPSocketIPollRecvCallback; } else { - s->pollParams.pollClass = POLL_CS_MAIN; - s->pollParams.flags = 0; - s->pollParams.lock = NULL; - s->pollParams.iPoll = NULL; + s->internalSendFn = AsyncTCPSocketSendCallback; + s->internalRecvFn = AsyncTCPSocketRecvCallback; } return s; @@ -2090,13 +2093,13 @@ AsyncSocketCreate(AsyncSocketPollParams *pollParams) // IN /* *---------------------------------------------------------------------------- * - * AsyncSocket_AttachToSSLSock -- + * AsyncTCPSocketAttachToSSLSock -- * - * AsyncSocket constructor. Wraps an existing SSLSock object with an - * AsyncSocket and returns the latter. + * AsyncTCPSocket constructor. Wraps an existing SSLSock object with an + * AsyncTCPSocket and returns the latter. * * Results: - * New AsyncSocket object or NULL on error. + * New AsyncTCPSocket object or NULL on error. * * Side effects: * Allocates memory, makes the underlying fd for the socket non-blocking. @@ -2104,12 +2107,12 @@ AsyncSocketCreate(AsyncSocketPollParams *pollParams) // IN *---------------------------------------------------------------------------- */ -AsyncSocket * -AsyncSocket_AttachToSSLSock(SSLSock sslSock, - AsyncSocketPollParams *pollParams, - int *outError) +static AsyncTCPSocket * +AsyncTCPSocketAttachToSSLSock(SSLSock sslSock, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT { - AsyncSocket *s; + AsyncTCPSocket *s; int fd; int error; @@ -2117,7 +2120,7 @@ AsyncSocket_AttachToSSLSock(SSLSock sslSock, fd = SSL_GetFd(sslSock); - if ((AsyncSocketMakeNonBlocking(fd)) != ASOCKERR_SUCCESS) { + if ((AsyncTCPSocketMakeNonBlocking(fd)) != ASOCKERR_SUCCESS) { int sysErr = ASOCK_LASTERROR(); Warning(ASOCKPREFIX "failed to make fd %d non-blocking!: %d, %s\n", fd, sysErr, Err_Errno2String(sysErr)); @@ -2125,19 +2128,14 @@ AsyncSocket_AttachToSSLSock(SSLSock sslSock, goto error; } - s = AsyncSocketCreate(pollParams); + s = AsyncTCPSocketCreate(pollParams); + AsyncTCPSocketSetState(s, AsyncSocketConnected); s->sslSock = sslSock; s->fd = fd; - s->asockType = ASYNCSOCKET_TYPE_SOCKET; - if (s->pollParams.iPoll == NULL) { - s->vt = &asyncStreamSocketVTable; - } else { - s->vt = &asyncStreamSocketIPollVTable; - } /* From now on socket is ours. */ SSL_SetCloseOnShutdownFlag(sslSock); - ASOCKLOG(1, s, ("new asock id %u attached to fd %d\n", s->id, s->fd)); + TCPSOCKLOG(1, s, ("new asock id %u attached to fd %d\n", s->base.id, s->fd)); return s; @@ -2153,28 +2151,28 @@ error: /* *---------------------------------------------------------------------------- * - * AsyncSocket_AttachToFd -- + * AsyncTCPSocketAttachToFd -- * - * AsyncSocket constructor. Wraps a valid socket fd with an AsyncSocket - * object. + * AsyncTCPSocket constructor. Wraps a valid socket fd with an + * AsyncTCPSocket object. * * Results: - * New AsyncSocket or NULL on error. + * New AsyncTCPSocket or NULL on error. * * Side effects: - * If function succeeds, fd is owned by AsyncSocket and should not be + * If function succeeds, fd is owned by AsyncTCPSocket and should not be * used (f.e. closed) anymore. * *---------------------------------------------------------------------------- */ -AsyncSocket * -AsyncSocket_AttachToFd(int fd, - AsyncSocketPollParams *pollParams, - int *outError) +static AsyncTCPSocket * +AsyncTCPSocketAttachToFd(int fd, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT { SSLSock sslSock; - AsyncSocket *asock; + AsyncTCPSocket *asock; /* * Create a new SSL socket object with the current socket @@ -2188,7 +2186,7 @@ AsyncSocket_AttachToFd(int fd, return NULL; } - asock = AsyncSocket_AttachToSSLSock(sslSock, pollParams, outError); + asock = AsyncTCPSocketAttachToSSLSock(sslSock, pollParams, outError); if (asock) { return asock; } @@ -2201,7 +2199,62 @@ AsyncSocket_AttachToFd(int fd, /* *---------------------------------------------------------------------------- * - * AsyncSocketUseNodelay -- + * AsyncSocket_AttachToFd -- + * + * Wrap a pre-existing file descriptor in an AsyncSocket entity. + * + * Results: + * New AsyncSocket or NULL on error. + * + * Side effects: + * If function succeeds, fd is owned by AsyncSocket and should not be + * used (f.e. closed) anymore. + * + *---------------------------------------------------------------------------- + */ + +AsyncSocket * +AsyncSocket_AttachToFd(int fd, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT +{ + AsyncTCPSocket *asock; + asock = AsyncTCPSocketAttachToFd(fd, pollParams, outError); + return BaseSocket(asock); +} + +/* + *---------------------------------------------------------------------------- + * + * AsyncSocket_AttachToSSLSock -- + * + * Wrap a pre-existing SSLSock in an AsyncSocket entity. + * + * Results: + * New AsyncSocket or NULL on error. + * + * Side effects: + * If function succeeds, fd is owned by AsyncSocket and should not be + * used (f.e. closed) anymore. + * + *---------------------------------------------------------------------------- + */ + +AsyncSocket * +AsyncSocket_AttachToSSLSock(SSLSock sslSock, // IN + AsyncSocketPollParams *pollParams, // IN + int *outError) // OUT +{ + AsyncTCPSocket *asock; + asock = AsyncTCPSocketAttachToSSLSock(sslSock, pollParams, outError); + return BaseSocket(asock); +} + + +/* + *---------------------------------------------------------------------------- + * + * AsyncTCPSocketUseNodelay -- * * Sets or unset TCP_NODELAY on the socket, which disables or * enables Nagle's algorithm, respectively. @@ -2216,22 +2269,21 @@ AsyncSocket_AttachToFd(int fd, *---------------------------------------------------------------------------- */ -int -AsyncSocketUseNodelay(AsyncSocket *asock, // IN/OUT: - Bool nodelay) // IN: +static int +AsyncTCPSocketUseNodelay(AsyncSocket *base, // IN/OUT: + Bool nodelay) // IN: { + AsyncTCPSocket *asock = TCPSocket(base); int flag = nodelay ? 1 : 0; - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); if (setsockopt(asock->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &flag, sizeof(flag)) != 0) { asock->genericErrno = Err_Errno(); LOG(0, (ASOCKPREFIX "could not set TCP_NODELAY, error %d: %s\n", Err_Errno(), Err_ErrString())); - AsyncSocketUnlock(asock); return ASOCKERR_GENERIC; } else { - AsyncSocketUnlock(asock); return ASOCKERR_SUCCESS; } } @@ -2240,7 +2292,7 @@ AsyncSocketUseNodelay(AsyncSocket *asock, // IN/OUT: /* *---------------------------------------------------------------------------- * - * AsyncSocketSetTCPTimeouts -- + * AsyncTCPSocketSetTCPTimeouts -- * * Allow caller to set a number of TCP-specific timeout * parameters on the socket for the active connection. @@ -2262,19 +2314,18 @@ AsyncSocketUseNodelay(AsyncSocket *asock, // IN/OUT: *---------------------------------------------------------------------------- */ -int -AsyncSocketSetTCPTimeouts(AsyncSocket *asock, // IN/OUT: - int keepIdle, // IN - int keepIntvl, // IN - int keepCnt) // IN +static int +AsyncTCPSocketSetTCPTimeouts(AsyncSocket *base, // IN/OUT: + int keepIdle, // IN + int keepIntvl, // IN + int keepCnt) // IN { #ifdef VMX86_SERVER + AsyncTCPSocket *asock = TCPSocket(base); int val; int opt; - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); val = keepIdle; opt = TCP_KEEPIDLE; @@ -2297,14 +2348,12 @@ AsyncSocketSetTCPTimeouts(AsyncSocket *asock, // IN/OUT: goto error; } - AsyncSocketUnlock(asock); return ASOCKERR_SUCCESS; error: asock->genericErrno = Err_Errno(); LOG(0, (ASOCKPREFIX "could not set TCP Timeout %d, error %d: %s\n", opt, Err_Errno(), Err_ErrString())); - AsyncSocketUnlock(asock); #endif return ASOCKERR_GENERIC; } @@ -2313,9 +2362,10 @@ error: /* *---------------------------------------------------------------------------- * - * AsyncSocketRecvSocket -- + * AsyncTCPSocketRegisterRecvCb -- * - * Does the socket specific portion of a AsyncSocket_Recv call. + * Register poll callbacks as required to be notified when data is ready + * following a AsyncTCPSocket_Recv call. * * Results: * ASOCKERR_*. @@ -2326,10 +2376,8 @@ error: *---------------------------------------------------------------------------- */ -int -AsyncSocketRecvSocket(AsyncSocket *asock, // IN: - void *buf, // IN: unused - int len) // IN: unused +static int +AsyncTCPSocketRegisterRecvCb(AsyncTCPSocket *asock) // IN: { int retVal = ASOCKERR_SUCCESS; @@ -2340,23 +2388,23 @@ AsyncSocketRecvSocket(AsyncSocket *asock, // IN: * Register the Poll callback */ - ASOCKLOG(3, asock, ("installing recv periodic poll callback\n")); + TCPSOCKLOG(3, asock, ("installing recv periodic poll callback\n")); - pollStatus = AsyncSocketPollAdd(asock, TRUE, + pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_READ | POLL_FLAG_PERIODIC, - asock->vt->recvCallback); + asock->internalRecvFn); if (pollStatus != VMWARE_STATUS_SUCCESS) { - ASOCKWARN(asock, ("failed to install recv callback!\n")); + TCPSOCKWARN(asock, ("failed to install recv callback!\n")); retVal = ASOCKERR_POLL; goto out; } asock->recvCb = TRUE; } - if (AsyncSocketHasDataPending(asock) && !asock->inRecvLoop) { - ASOCKLOG(0, asock, ("installing recv RTime poll callback\n")); - if (AsyncSocketPollAdd(asock, FALSE, 0, asock->vt->recvCallback, 0) != + if (AsyncTCPSocketHasDataPending(asock) && !asock->inRecvLoop) { + TCPSOCKLOG(0, asock, ("installing recv RTime poll callback\n")); + if (AsyncTCPSocketPollAdd(asock, FALSE, 0, asock->internalRecvFn, 0) != VMWARE_STATUS_SUCCESS) { retVal = ASOCKERR_POLL; goto out; @@ -2372,12 +2420,12 @@ out: /* *---------------------------------------------------------------------------- * - * AsyncSocket_Recv -- + * AsyncTCPSocket_Recv -- * * Registers a callback that will fire once the specified amount of data * has been received on the socket. * - * In the case of AsyncSocket_RecvPartial, the callback is fired + * In the case of AsyncTCPSocket_RecvPartial, the callback is fired * once all or part of the data has been received on the socket. * * Data that was not retrieved at the last call of SSL_read() could still @@ -2386,20 +2434,20 @@ out: * for reading since there might not be any data in the underlying network * socket layer. Hence in the read callback, we keep spinning until all * all the data buffered inside the SSL layer is retrieved before - * returning to the poll loop (See AsyncSocketFillRecvBuffer()). + * returning to the poll loop (See AsyncTCPSocketFillRecvBuffer()). * * However, we might not have come out of Poll in the first place, e.g. - * if this is the first call to AsyncSocket_Recv() after creating a new + * if this is the first call to AsyncTCPSocket_Recv() after creating a new * connection. In this situation, if there is buffered SSL data pending, * we have to schedule an RTTime callback to force retrieval of the data. - * This could also happen if the client calls AsyncSocket_RecvBlocking, + * This could also happen if the client calls AsyncTCPSocket_RecvBlocking, * some data is left in the SSL layer, and the client then calls - * AsyncSocket_Recv. We use the inRecvLoop variable to detect and handle + * AsyncTCPSocket_Recv. We use the inRecvLoop variable to detect and handle * this condition, i.e., if inRecvLoop is FALSE, we need to schedule the * RTime callback. * * TCP usage: - * AsyncSocket_Recv(AsyncSocket *asock, + * AsyncTCPSocket_Recv(AsyncTCPSocket *asock, * void *buf, * int len, * AsyncSocketRecvFn recvFn, @@ -2414,27 +2462,22 @@ out: *---------------------------------------------------------------------------- */ -int -AsyncSocketRecv(AsyncSocket *asock, // IN: - void *buf, // IN: unused - int len, // IN: unused - Bool fireOnPartial, // IN: - void *cb, // IN: - void *cbData) // IN: +static int +AsyncTCPSocketRecv(AsyncSocket *base, // IN: + void *buf, // IN: unused + int len, // IN: unused + Bool fireOnPartial, // IN: + void *cb, // IN: + void *cbData) // IN: { - AsyncSocketRecvFn recvFn = NULL; - void *clientData = NULL; + AsyncTCPSocket *asock = TCPSocket(base); int retVal; - if (!asock->errorFn) { - ASOCKWARN(asock, ("%s: no registered error handler!\n", __FUNCTION__)); - + if (!asock->base.errorFn) { + TCPSOCKWARN(asock, ("%s: no registered error handler!\n", __FUNCTION__)); return ASOCKERR_INVAL; } - recvFn = cb; - clientData = cbData; - /* * XXX We might want to allow passing NULL for the recvFn, to indicate that * the client is no longer interested in reading from the socket. This @@ -2442,57 +2485,40 @@ AsyncSocketRecv(AsyncSocket *asock, // IN: * then the client->server half of the connection is closed. */ - if (!buf || !recvFn || len <= 0) { + if (!buf || !cb || len <= 0) { Warning(ASOCKPREFIX "Recv called with invalid arguments!\n"); - return ASOCKERR_INVAL; } - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); - if (asock->state != AsyncSocketConnected) { - ASOCKWARN(asock, ("recv called but state is not connected!\n")); - retVal = ASOCKERR_NOTCONNECTED; - goto outHaveLock; + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { + TCPSOCKWARN(asock, ("recv called but state is not connected!\n")); + return ASOCKERR_NOTCONNECTED; } if (asock->inBlockingRecv) { - ASOCKWARN(asock, ("Recv called while a blocking recv is pending.\n")); - retVal = ASOCKERR_INVAL; - goto outHaveLock; - } - - if (asock->recvBuf && asock->recvPos != 0) { - ASOCKWARN(asock, ("Recv called -- partially read buffer discarded.\n")); + TCPSOCKWARN(asock, ("Recv called while a blocking recv is pending.\n")); + return ASOCKERR_INVAL; } - ASSERT(asock->vt); - ASSERT(asock->vt->recvInternal); - retVal = asock->vt->recvInternal(asock, buf, len); + retVal = AsyncTCPSocketRegisterRecvCb(asock); if (retVal != ASOCKERR_SUCCESS) { - goto outHaveLock; + return retVal; } - asock->recvBuf = buf; - asock->recvFn = recvFn; - asock->recvLen = len; - asock->recvFireOnPartial = fireOnPartial; - asock->recvPos = 0; - asock->clientData = clientData; - retVal = ASOCKERR_SUCCESS; - -outHaveLock: - AsyncSocketUnlock(asock); - return retVal; + AsyncSocketSetRecvBuf(BaseSocket(asock), buf, len, fireOnPartial, + cb, cbData); + return ASOCKERR_SUCCESS; } /* *---------------------------------------------------------------------------- * - * AsyncSocketRecvPassedFd -- + * AsyncTCPSocketRecvPassedFd -- * - * See AsyncSocket_Recv. Besides that it allows for receiving one + * See AsyncTCPSocket_Recv. Besides that it allows for receiving one * file descriptor... * * Results: @@ -2504,35 +2530,33 @@ outHaveLock: *---------------------------------------------------------------------------- */ -int -AsyncSocketRecvPassedFd(AsyncSocket *asock, // IN/OUT: socket - void *buf, // OUT: buffer with data - int len, // IN: length - void *cb, // IN: completion calback - void *cbData) // IN: callback's data +static int +AsyncTCPSocketRecvPassedFd(AsyncSocket *base, // IN/OUT: socket + void *buf, // OUT: buffer with data + int len, // IN: length + void *cb, // IN: completion calback + void *cbData) // IN: callback's data { + AsyncTCPSocket *asock = TCPSocket(base); int err; - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - - if (!asock->errorFn) { - ASOCKWARN(asock, ("%s: no registered error handler!\n", __FUNCTION__)); + if (!asock->base.errorFn) { + TCPSOCKWARN(asock, ("%s: no registered error handler!\n", __FUNCTION__)); return ASOCKERR_INVAL; } - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); if (asock->passFd.fd != -1) { SSLGeneric_close(asock->passFd.fd); asock->passFd.fd = -1; } asock->passFd.expected = TRUE; - err = AsyncSocket_Recv(asock, buf, len, cb, cbData); + err = AsyncTCPSocketRecv(BaseSocket(asock), buf, len, FALSE, cb, cbData); if (err != ASOCKERR_SUCCESS) { asock->passFd.expected = FALSE; } - AsyncSocketUnlock(asock); return err; } @@ -2541,7 +2565,7 @@ AsyncSocketRecvPassedFd(AsyncSocket *asock, // IN/OUT: socket /* *---------------------------------------------------------------------------- * - * AsyncSocketPoll -- + * AsyncTCPSocketPoll -- * * Blocks on the specified socket until there's data pending or a * timeout occurs. @@ -2562,10 +2586,10 @@ AsyncSocketRecvPassedFd(AsyncSocket *asock, // IN/OUT: socket */ static int -AsyncSocketPoll(AsyncSocket *s, // IN: - Bool read, // IN: - int timeoutMS, // IN: - AsyncSocket **outAsock) // OUT: +AsyncTCPSocketPoll(AsyncTCPSocket *s, // IN: + Bool read, // IN: + int timeoutMS, // IN: + AsyncTCPSocket **outAsock) // OUT: { #ifndef _WIN32 struct pollfd p[2]; @@ -2581,17 +2605,15 @@ AsyncSocketPoll(AsyncSocket *s, // IN: struct fd_set rwfds; struct fd_set exceptfds; #endif - AsyncSocket *asock[2]; + AsyncTCPSocket *asock[2]; int numSock = 0; int i; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); ASSERT(*outAsock == NULL); if (read && s->fd == -1) { if (!s->listenAsock4 && !s->listenAsock6) { - ASSERT(FALSE); - ASOCKLG0(s, ("%s: Failed to find listener socket.\n", __FUNCTION__)); + TCPSOCKLG0(s, ("%s: Failed to find listener socket.\n", __FUNCTION__)); return ASOCKERR_GENERIC; } @@ -2619,7 +2641,9 @@ AsyncSocketPoll(AsyncSocket *s, // IN: p[i].events = read ? POLLIN : POLLOUT; } + AsyncTCPSocketUnlock(s); retval = poll(p, numSock, timeoutMS); + AsyncTCPSocketLock(s); #else tv.tv_sec = timeoutMS / 1000; tv.tv_usec = (timeoutMS % 1000) * 1000; @@ -2632,8 +2656,10 @@ AsyncSocketPoll(AsyncSocket *s, // IN: FD_SET(asock[i]->fd, &exceptfds); } + AsyncTCPSocketUnlock(s); retval = select(1, read ? &rwfds : NULL, read ? NULL : &rwfds, &exceptfds, timeoutMS >= 0 ? &tv : NULL); + AsyncTCPSocketLock(s); #endif switch (retval) { @@ -2665,7 +2691,7 @@ AsyncSocketPoll(AsyncSocket *s, // IN: (void *) &sockErr, (void *) &sockErrLen) == 0) { if (sockErr) { asock[i]->genericErrno = sockErr; - ASOCKLG0(asock[i], + TCPSOCKLG0(asock[i], ("%s: Socket error lookup returned %d: %s\n", __FUNCTION__, sockErr, Err_Errno2String(sockErr))); @@ -2673,7 +2699,7 @@ AsyncSocketPoll(AsyncSocket *s, // IN: } else { sysErr = ASOCK_LASTERROR(); asock[i]->genericErrno = sysErr; - ASOCKLG0(asock[i], + TCPSOCKLG0(asock[i], ("%s: Last socket error %d: %s\n", __FUNCTION__, sysErr, Err_Errno2String(sysErr))); } @@ -2703,15 +2729,15 @@ AsyncSocketPoll(AsyncSocket *s, // IN: } #endif - ASOCKWARN(s, ("%s: Failed to return a ready socket.\n", - __FUNCTION__)); + TCPSOCKWARN(s, ("%s: Failed to return a ready socket.\n", + __FUNCTION__)); return ASOCKERR_GENERIC; } case 0: /* * No sockets were ready within the specified time. */ - ASOCKLG0(s, ("%s: Timeout waiting for a ready socket.\n", + TCPSOCKLG0(s, ("%s: Timeout waiting for a ready socket.\n", __FUNCTION__)); return ASOCKERR_TIMEOUT; @@ -2723,15 +2749,15 @@ AsyncSocketPoll(AsyncSocket *s, // IN: * We were somehow interrupted by signal. Let's loop and retry. */ - ASOCKLG0(s, ("%s: Socket interrupted by a signal.\n", + TCPSOCKLG0(s, ("%s: Socket interrupted by a signal.\n", __FUNCTION__)); continue; } s->genericErrno = sysErr; - ASOCKLG0(s, ("%s: Failed with error %d: %s\n", __FUNCTION__, sysErr, - Err_Errno2String(sysErr))); + TCPSOCKLG0(s, ("%s: Failed with error %d: %s\n", __FUNCTION__, sysErr, + Err_Errno2String(sysErr))); return ASOCKERR_GENERIC; } default: @@ -2744,12 +2770,12 @@ AsyncSocketPoll(AsyncSocket *s, // IN: /* *---------------------------------------------------------------------------- * - * AsyncSocket_RecvBlocking -- - * AsyncSocket_RecvPartialBlocking -- - * AsyncSocket_SendBlocking -- + * AsyncTCPSocketRecvBlocking -- + * AsyncTCPSocketRecvPartialBlocking -- + * AsyncTCPSocketSendBlocking -- * * Implement "blocking + timeout" operations on the socket. These are - * simple wrappers around the AsyncSocketBlockingWork function, which + * simple wrappers around the AsyncTCPSocketBlockingWork function, which * operates on the actual non-blocking socket, using poll to determine * when it's ok to keep reading/writing. If we can't finish within the * specified time, we give up and return the ASOCKERR_TIMEOUT error. @@ -2769,43 +2795,46 @@ AsyncSocketPoll(AsyncSocket *s, // IN: *---------------------------------------------------------------------------- */ -int -AsyncSocket_RecvBlocking(AsyncSocket *s, - void *buf, - int len, - int *received, - int timeoutMS) +static int +AsyncTCPSocketRecvBlocking(AsyncSocket *base, // IN + void *buf, // OUT + int len, // IN + int *received, // OUT + int timeoutMS) // IN { - return AsyncSocketBlockingWork(s, TRUE, buf, len, received, timeoutMS, - FALSE); + AsyncTCPSocket *s = TCPSocket(base); + return AsyncTCPSocketBlockingWork(s, TRUE, buf, len, received, timeoutMS, + FALSE); } -int -AsyncSocket_RecvPartialBlocking(AsyncSocket *s, - void *buf, - int len, - int *received, - int timeoutMS) +static int +AsyncTCPSocketRecvPartialBlocking(AsyncSocket *base, // IN + void *buf, // OUT + int len, // IN + int *received, // OUT + int timeoutMS) // IN { - return AsyncSocketBlockingWork(s, TRUE, buf, len, received, timeoutMS, - TRUE); + AsyncTCPSocket *s = TCPSocket(base); + return AsyncTCPSocketBlockingWork(s, TRUE, buf, len, received, timeoutMS, + TRUE); } -int -AsyncSocket_SendBlocking(AsyncSocket *s, - void *buf, - int len, - int *sent, - int timeoutMS) +static int +AsyncTCPSocketSendBlocking(AsyncSocket *base, // IN + void *buf, // OUT + int len, // IN + int *sent, // OUT + int timeoutMS) // IN { - return AsyncSocketBlockingWork(s, FALSE, buf, len, sent, timeoutMS, FALSE); + AsyncTCPSocket *s = TCPSocket(base); + return AsyncTCPSocketBlockingWork(s, FALSE, buf, len, sent, timeoutMS, FALSE); } /* *---------------------------------------------------------------------------- * - * AsyncSocketBlockingWork -- + * AsyncTCPSocketBlockingWork -- * * Try to complete the specified read/write operation within the * specified time. @@ -2818,30 +2847,26 @@ AsyncSocket_SendBlocking(AsyncSocket *s, *---------------------------------------------------------------------------- */ -int -AsyncSocketBlockingWork(AsyncSocket *s, // IN: - Bool read, // IN: - void *buf, // IN/OUT: - int len, // IN: - int *completed, // OUT: - int timeoutMS, // IN: - Bool partial) // IN: +static int +AsyncTCPSocketBlockingWork(AsyncTCPSocket *s, // IN: + Bool read, // IN: + void *buf, // IN/OUT: + int len, // IN: + int *completed, // OUT: + int timeoutMS, // IN: + Bool partial) // IN: { VmTimeType now, done; int sysErr; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(s->asockType != ASYNCSOCKET_TYPE_PROXYSOCKET); - if (s == NULL || buf == NULL || len <= 0) { Warning(ASOCKPREFIX "Recv called with invalid arguments!\n"); return ASOCKERR_INVAL; } - if (s->state != AsyncSocketConnected) { - ASOCKWARN(s, ("recv called but state is not connected!\n")); - + if (AsyncTCPSocketGetState(s) != AsyncSocketConnected) { + TCPSOCKWARN(s, ("recv called but state is not connected!\n")); return ASOCKERR_NOTCONNECTED; } @@ -2852,10 +2877,10 @@ AsyncSocketBlockingWork(AsyncSocket *s, // IN: done = now + timeoutMS; do { int numBytes, error; - AsyncSocket *asock = NULL; + AsyncTCPSocket *asock = NULL; - if ((error = AsyncSocketPoll(s, read, done - now, &asock)) != - ASOCKERR_SUCCESS) { + error = AsyncTCPSocketPoll(s, read, done - now, &asock); + if (error != ASOCKERR_SUCCESS) { return error; } @@ -2871,13 +2896,13 @@ AsyncSocketBlockingWork(AsyncSocket *s, // IN: } buf = (uint8*)buf + numBytes; } else if (numBytes == 0) { - ASOCKLG0(s, ("blocking %s detected peer closed connection\n", - read ? "recv" : "send")); + TCPSOCKLG0(s, ("blocking %s detected peer closed connection\n", + read ? "recv" : "send")); return ASOCKERR_REMOTE_DISCONNECT; } else if ((sysErr = ASOCK_LASTERROR()) != ASOCK_EWOULDBLOCK) { s->genericErrno = sysErr; - ASOCKWARN(s, ("blocking %s error %d: %s\n", read ? "recv" : "send", - sysErr, Err_Errno2String(sysErr))); + TCPSOCKWARN(s, ("blocking %s error %d: %s\n", read ? "recv" : "send", + sysErr, Err_Errno2String(sysErr))); return ASOCKERR_GENERIC; } @@ -2892,83 +2917,7 @@ AsyncSocketBlockingWork(AsyncSocket *s, // IN: /* *---------------------------------------------------------------------------- * - * AsyncSocketSendSocket -- - * - * Does the socket specific portion of a AsyncSocket_Send call. - * - * Results: - * ASOCKERR_*. - * - * Side effects: - * May register poll callback or perform I/O. - * - *---------------------------------------------------------------------------- - */ - -int -AsyncSocketSendSocket(AsyncSocket *asock, // IN: - Bool bufferListWasEmpty, // IN: - void *buf, // IN: unused - int len) // IN: unused -{ - int retVal = ASOCKERR_SUCCESS; - - if (bufferListWasEmpty && !asock->sendCb) { -#ifdef _WIN32 - /* - * If the send buffer list was empty, we schedule a one-time callback - * to "prime" the output. This is necessary to support the FD_WRITE - * network event semantic for sockets on Windows (see WSAEventSelect - * documentation). The event won't signal unless a previous write() on - * the socket failed with WSAEWOULDBLOCK, so we have to perform at - * least one partial write before we can start polling for write. - * - * XXX: This can be a device callback once all poll implementations - * know to get around this Windows quirk. Both PollVMX and PollDefault - * already make 0-byte send() to force WSAEWOULDBLOCK. - */ - - if (AsyncSocketPollAdd(asock, FALSE, 0, asock->vt->sendCallback, - asock->pollParams.iPoll != NULL ? 1 : 0) - != VMWARE_STATUS_SUCCESS) { - retVal = ASOCKERR_POLL; - return retVal; - } - asock->sendCbTimer = TRUE; - asock->sendCb = TRUE; -#else - if (asock->sendLowLatency) { - /* - * For low-latency sockets, call the callback directly from - * this thread. It is non-blocking and will schedule device - * callbacks if necessary to complete the operation. - * - * Unfortunately we can't make this the default as current - * consumers of asyncsocket are not expecting the completion - * callback to be invoked prior to the call to - * AsyncSocket_Send() returning. - */ - asock->vt->sendCallback((void *)asock); - } else { - if (AsyncSocketPollAdd(asock, TRUE, POLL_FLAG_WRITE, - asock->vt->sendCallback) - != VMWARE_STATUS_SUCCESS) { - retVal = ASOCKERR_POLL; - return retVal; - } - asock->sendCb = TRUE; - } -#endif - } - - return retVal; -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketSend -- + * AsyncTCPSocketSend -- * * Queues the provided data for sending on the socket. If a send callback * is provided, the callback is fired after the data has been written to @@ -2992,16 +2941,18 @@ AsyncSocketSendSocket(AsyncSocket *asock, // IN: *---------------------------------------------------------------------------- */ -int -AsyncSocketSend(AsyncSocket *asock, - void *buf, - int len, - AsyncSocketSendFn sendFn, - void *clientData) +static int +AsyncTCPSocketSend(AsyncSocket *base, // IN + void *buf, // IN + int len, // IN + AsyncSocketSendFn sendFn, // IN + void *clientData) // IN { + AsyncTCPSocket *asock = TCPSocket(base); int retVal; Bool bufferListWasEmpty = FALSE; SendBufList **pcur; + SendBufList *newBuf; /* * Note: I think it should be fine to send with a length of zero and a @@ -3010,42 +2961,91 @@ AsyncSocketSend(AsyncSocket *asock, * the <= zero check instead of just a < zero check. --Jeremy. */ - if (!asock || !buf || len <= 0) { - Warning(ASOCKPREFIX "Send called with invalid arguments! asynchSock: %p " - "buffer: %p length: %d\n", asock, buf, len); + if (!buf || len <= 0) { + Warning(ASOCKPREFIX "Send called with invalid arguments!" + "buffer: %p length: %d\n", buf, len); return ASOCKERR_INVAL; } LOG(2, ("%s: sending %d bytes\n", __FUNCTION__, len)); - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); - if (asock->state != AsyncSocketConnected) { - ASOCKWARN(asock, ("send called but state is not connected!\n")); - retVal = ASOCKERR_NOTCONNECTED; - goto outHaveLock; + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { + TCPSOCKWARN(asock, ("send called but state is not connected!\n")); + return ASOCKERR_NOTCONNECTED; } - ASSERT(asock->vt); - ASSERT(asock->vt->prepareSend); - retVal = asock->vt->prepareSend(asock, buf, len, sendFn, clientData, - &bufferListWasEmpty); - if (retVal != ASOCKERR_SUCCESS) { - ASOCKLOG(1, asock, ("Failed to prepare buffer:%p for send. Error:%d\n", - buf, retVal)); - goto outUndoAppend; - } + /* + * Allocate and initialize new send buffer entry + */ + newBuf = Util_SafeCalloc(1, sizeof *newBuf); + newBuf->buf = buf; + newBuf->len = len; + newBuf->sendFn = sendFn; + newBuf->clientData = clientData; - ASSERT(asock->vt->sendInternal); - retVal = asock->vt->sendInternal(asock, bufferListWasEmpty, buf, len); - if (retVal != ASOCKERR_SUCCESS) { - ASOCKLOG(1, asock, ("Failed to send buffer:%p. Error:%d\n", buf, retVal)); - goto outUndoAppend; + /* + * Append new send buffer to the tail of list. + */ + *asock->sendBufTail = newBuf; + asock->sendBufTail = &(newBuf->next); + bufferListWasEmpty = (asock->sendBufList == newBuf); + + if (bufferListWasEmpty && !asock->sendCb) { +#ifdef _WIN32 + /* + * If the send buffer list was empty, we schedule a one-time callback + * to "prime" the output. This is necessary to support the FD_WRITE + * network event semantic for sockets on Windows (see WSAEventSelect + * documentation). The event won't signal unless a previous write() on + * the socket failed with WSAEWOULDBLOCK, so we have to perform at + * least one partial write before we can start polling for write. + * + * XXX: This can be a device callback once all poll implementations + * know to get around this Windows quirk. Both PollVMX and PollDefault + * already make 0-byte send() to force WSAEWOULDBLOCK. + */ + + if (AsyncTCPSocketPollAdd(asock, FALSE, 0, asock->internalSendFn, + AsyncTCPSocketPollParams(asock)->iPoll != NULL + ? 1 : 0) + != VMWARE_STATUS_SUCCESS) { + retVal = ASOCKERR_POLL; + TCPSOCKLOG(1, asock, ("Failed to register poll callback for send\n")); + goto outUndoAppend; + } + asock->sendCbTimer = TRUE; + asock->sendCb = TRUE; +#else + if (asock->sendLowLatency) { + /* + * For low-latency sockets, call the callback directly from + * this thread. It is non-blocking and will schedule device + * callbacks if necessary to complete the operation. + * + * Unfortunately we can't make this the default as current + * consumers of asyncsocket are not expecting the completion + * callback to be invoked prior to the call to + * AsyncTCPSocket_Send() returning. + */ + asock->internalSendFn((void *)asock); + } else { + if (AsyncTCPSocketPollAdd(asock, TRUE, POLL_FLAG_WRITE, + asock->internalSendFn) + != VMWARE_STATUS_SUCCESS) { + retVal = ASOCKERR_POLL; + TCPSOCKLOG(1, asock, + ("Failed to register poll callback for send\n")); + goto outUndoAppend; + } + asock->sendCb = TRUE; + } +#endif } - retVal = ASOCKERR_SUCCESS; - goto outHaveLock; + return ASOCKERR_SUCCESS; outUndoAppend: /* @@ -3067,8 +3067,6 @@ outUndoAppend: } } -outHaveLock: - AsyncSocketUnlock(asock); return retVal; } @@ -3076,7 +3074,7 @@ outHaveLock: /* *---------------------------------------------------------------------------- * - * AsyncSocketResolveAddr -- + * AsyncTCPSocketResolveAddr -- * * Resolves a hostname and port. * @@ -3088,14 +3086,15 @@ outHaveLock: * *---------------------------------------------------------------------------- */ -int -AsyncSocketResolveAddr(const char *hostname, - unsigned int port, - int family, - Bool passive, - struct sockaddr_storage *addr, - socklen_t *addrLen, - char **addrString) + +static int +AsyncTCPSocketResolveAddr(const char *hostname, // IN + unsigned int port, // IN + int family, // IN + Bool passive, // IN + struct sockaddr_storage *addr, // OUT + socklen_t *addrLen, // OUT + char **addrString) // OUT { struct addrinfo hints; struct addrinfo *aiTop = NULL; @@ -3182,76 +3181,7 @@ bye: /* *---------------------------------------------------------------------------- * - * AsyncSocketCheckAndDispatchRecv -- - * - * Check if the recv buffer is full and dispatch the client callback. - * - * Handles the possibility that the client registers a new receive buffer - * or closes the socket in their callback. - * - * Results: - * TRUE if the socket was closed or the receive was cancelled, - * FALSE if the caller should continue to try to receive data. - * - * Side effects: - * Could fire recv completion or trigger socket destruction. - * - *---------------------------------------------------------------------------- - */ - -Bool -AsyncSocketCheckAndDispatchRecv(AsyncSocket *s, // IN - int *result) // OUT -{ - ASSERT(s); - ASSERT(result); - ASSERT(s->recvFn); - ASSERT(s->recvBuf); - ASSERT(s->recvLen > 0); - ASSERT(s->recvPos <= s->recvLen); - - if (s->recvPos == s->recvLen || s->recvFireOnPartial) { - void *recvBuf = s->recvBuf; - ASOCKLOG(3, s, ("recv buffer full, calling recvFn\n")); - - /* - * We do this dance in case the handler frees the buffer (so - * that there's no possible window where there are dangling - * references here. Obviously if the handler frees the buffer, - * but them fails to register a new one, we'll put back the - * dangling reference in the automatic reset case below, but - * there's currently a limit to how far we go to shield clients - * who use our API in a broken way. - */ - - s->recvBuf = NULL; - s->recvFn(recvBuf, s->recvPos, s, s->clientData); - if (s->state == AsyncSocketClosed) { - ASOCKLG0(s, ("owner closed connection in recv callback\n")); - *result = ASOCKERR_CLOSED; - return TRUE; - } else if (s->recvFn == NULL && s->recvLen == 0) { - /* - * Further recv is cancelled from within the last recvFn, see - * AsyncSocket_CancelRecv(). So exit from the loop. - */ - *result = ASOCKERR_SUCCESS; - return TRUE; - } else if (s->recvLen - s->recvPos == 0) { - /* Automatically reset keeping the current handler */ - s->recvPos = 0; - s->recvBuf = recvBuf; - } - } - - return FALSE; -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketFillRecvBuffer -- + * AsyncTCPSocketFillRecvBuffer -- * * Called when an asock has data ready to be read via the poll callback. * @@ -3267,8 +3197,8 @@ AsyncSocketCheckAndDispatchRecv(AsyncSocket *s, // IN *---------------------------------------------------------------------------- */ -int -AsyncSocketFillRecvBuffer(AsyncSocket *s) +static int +AsyncTCPSocketFillRecvBuffer(AsyncTCPSocket *s) // IN { int recvd; int needed; @@ -3276,9 +3206,8 @@ AsyncSocketFillRecvBuffer(AsyncSocket *s) int result; int pending = 0; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(AsyncSocketIsLocked(s)); - ASSERT(s->state == AsyncSocketConnected); + ASSERT(AsyncTCPSocketIsLocked(s)); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); /* * When a socket has received all its desired content and FillRecvBuffer is @@ -3289,17 +3218,17 @@ AsyncSocketFillRecvBuffer(AsyncSocket *s) * called twice for the same receive event. */ - needed = s->recvLen - s->recvPos; - if (!s->recvBuf && needed == 0) { + needed = s->base.recvLen - s->base.recvPos; + if (!s->base.recvBuf && needed == 0) { return ASOCKERR_SUCCESS; } ASSERT(needed > 0); - AsyncSocketAddRef(s); + AsyncTCPSocketAddRef(s); /* - * See comment in AsyncSocket_Recv + * See comment in AsyncTCPSocket_Recv */ s->inRecvLoop = TRUE; @@ -3314,27 +3243,30 @@ AsyncSocketFillRecvBuffer(AsyncSocket *s) int fd; recvd = SSL_RecvDataAndFd(s->sslSock, - (uint8 *) s->recvBuf + s->recvPos, + (uint8 *) s->base.recvBuf + + s->base.recvPos, needed, &fd); if (fd != -1) { s->passFd.fd = fd; s->passFd.expected = FALSE; } } else { - recvd = SSL_Read(s->sslSock, (uint8 *) s->recvBuf + s->recvPos, + recvd = SSL_Read(s->sslSock, + (uint8 *) s->base.recvBuf + + s->base.recvPos, needed); } - ASOCKLOG(3, s, ("need\t%d\trecv\t%d\tremain\t%d\n", needed, recvd, - needed - recvd)); + TCPSOCKLOG(3, s, ("need\t%d\trecv\t%d\tremain\t%d\n", needed, recvd, + needed - recvd)); if (recvd > 0) { s->sslConnected = TRUE; - s->recvPos += recvd; - if (AsyncSocketCheckAndDispatchRecv(s, &result)) { + s->base.recvPos += recvd; + if (AsyncSocketCheckAndDispatchRecv(&s->base, &result)) { goto exit; } } else if (recvd == 0) { - ASOCKLG0(s, ("recv detected client closed connection\n")); + TCPSOCKLG0(s, ("recv detected client closed connection\n")); /* * We treat this as an error so that the owner can detect closing * of connection by peer (via the error handler callback). @@ -3342,10 +3274,10 @@ AsyncSocketFillRecvBuffer(AsyncSocket *s) result = ASOCKERR_REMOTE_DISCONNECT; goto exit; } else if ((sysErr = ASOCK_LASTERROR()) == ASOCK_EWOULDBLOCK) { - ASOCKLOG(4, s, ("recv would block\n")); + TCPSOCKLOG(4, s, ("recv would block\n")); break; } else { - ASOCKLG0(s, ("recv error %d: %s\n", sysErr, + TCPSOCKLG0(s, ("recv error %d: %s\n", sysErr, Err_Errno2String(sysErr))); s->genericErrno = sysErr; result = ASOCKERR_GENERIC; @@ -3359,7 +3291,7 @@ AsyncSocketFillRecvBuffer(AsyncSocket *s) * buffered in userspace already (SSL_Pending). */ - needed = s->recvLen - s->recvPos; + needed = s->base.recvLen - s->base.recvPos; ASSERT(needed > 0); pending = SSL_Pending(s->sslSock); @@ -3384,7 +3316,7 @@ AsyncSocketFillRecvBuffer(AsyncSocket *s) exit: s->inRecvLoop = FALSE; - AsyncSocketRelease(s, FALSE); + AsyncTCPSocketRelease(s); return result; } @@ -3393,7 +3325,7 @@ exit: /* *---------------------------------------------------------------------------- * - * AsyncSocketDispatchSentBuffer -- + * AsyncTCPSocketDispatchSentBuffer -- * * Pop off the head of the send buffer list and call its callback. * @@ -3406,9 +3338,11 @@ exit: *---------------------------------------------------------------------------- */ -void -AsyncSocketDispatchSentBuffer(AsyncSocket *s) +static int +AsyncTCPSocketDispatchSentBuffer(AsyncTCPSocket *s) // IN { + int result = ASOCKERR_SUCCESS; + /* * We're done with the current buffer, so pop it off and nuke it. * We do the list management *first*, so that the list is in a @@ -3423,31 +3357,34 @@ AsyncSocketDispatchSentBuffer(AsyncSocket *s) s->sendBufTail = &(s->sendBufList); } s->sendPos = 0; - free(tmp.encodedBuf); free(head); if (tmp.sendFn) { /* - * XXX - * Firing the send completion could trigger the socket's - * destruction (since the callback could turn around and call - * AsyncSocket_Close()). Since we're in the middle of a loop on - * the asock's queue, we avoid a use-after-free by deferring - * the actual freeing of the asock structure. This is shady but - * it works. --rrdharan + * Firing the send completion cannot trigger immediate + * destruction of the socket because we hold a refCount across + * this and all other application callbacks. If the socket is + * closed, however, we need to bubble the information up to the + * caller in the same way as we do in the Recv callback case. */ - - tmp.sendFn(tmp.buf, tmp.len, s, tmp.clientData); + ASSERT(s->base.refCount > 1); + tmp.sendFn(tmp.buf, tmp.len, BaseSocket(s), tmp.clientData); + if (AsyncTCPSocketGetState(s) == AsyncSocketClosed) { + TCPSOCKLG0(s, ("owner closed connection in send callback\n")); + result = ASOCKERR_CLOSED; + } } + + return result; } /* *---------------------------------------------------------------------------- * - * AsyncSocketWriteBuffers -- + * AsyncTCPSocketWriteBuffers -- * - * The meat of AsyncSocket's sending functionality. This function + * The meat of AsyncTCPSocket's sending functionality. This function * actually writes to the wire assuming there's space in the buffers * for the socket. * @@ -3461,52 +3398,49 @@ AsyncSocketDispatchSentBuffer(AsyncSocket *s) */ static int -AsyncSocketWriteBuffers(AsyncSocket *s) +AsyncTCPSocketWriteBuffers(AsyncTCPSocket *s) // IN { int result; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(AsyncSocketIsLocked(s)); + ASSERT(AsyncTCPSocketIsLocked(s)); if (s->sendBufList == NULL) { return ASOCKERR_SUCCESS; /* Vacuously true */ } - if (s->state != AsyncSocketConnected) { - ASOCKWARN(s, ("write buffers on a disconnected socket (%d)!\n", - s->state)); + if (AsyncTCPSocketGetState(s) != AsyncSocketConnected) { + TCPSOCKWARN(s, ("write buffers on a disconnected socket!\n")); return ASOCKERR_GENERIC; } - AsyncSocketAddRef(s); + AsyncTCPSocketAddRef(s); - while (s->sendBufList && s->state == AsyncSocketConnected) { + while (s->sendBufList && AsyncTCPSocketGetState(s) == AsyncSocketConnected) { SendBufList *head = s->sendBufList; int error = 0; int sent = 0; int left = head->len - s->sendPos; int sizeToSend = head->len; - if (head->encodedBuf) { - sent = SSL_Write(s->sslSock, - (uint8 *) head->encodedBuf + s->sendPos, left); - } else { - sent = SSL_Write(s->sslSock, - (uint8 *) head->buf + s->sendPos, left); - } - ASOCKLOG(3, s, ("left\t%d\tsent\t%d\tremain\t%d\n", + sent = SSL_Write(s->sslSock, + (uint8 *) head->buf + s->sendPos, left); + + TCPSOCKLOG(3, s, ("left\t%d\tsent\t%d\tremain\t%d\n", left, sent, left - sent)); if (sent > 0) { s->sendBufFull = FALSE; s->sslConnected = TRUE; if ((s->sendPos += sent) == sizeToSend) { - AsyncSocketDispatchSentBuffer(s); + result = AsyncTCPSocketDispatchSentBuffer(s); + if (result != ASOCKERR_SUCCESS) { + goto exit; + } } } else if (sent == 0) { - ASOCKLG0(s, ("socket write() should never return 0.\n")); + TCPSOCKLG0(s, ("socket write() should never return 0.\n")); NOT_REACHED(); } else if ((error = ASOCK_LASTERROR()) != ASOCK_EWOULDBLOCK) { - ASOCKLG0(s, ("send error %d: %s\n", error, Err_Errno2String(error))); + TCPSOCKLG0(s, ("send error %d: %s\n", error, Err_Errno2String(error))); s->genericErrno = error; result = ASOCKERR_GENERIC; goto exit; @@ -3527,7 +3461,7 @@ AsyncSocketWriteBuffers(AsyncSocket *s) result = ASOCKERR_SUCCESS; exit: - AsyncSocketRelease(s, FALSE); + AsyncTCPSocketRelease(s); return result; } @@ -3536,12 +3470,12 @@ exit: /* *---------------------------------------------------------------------------- * - * AsyncSocketAcceptInternal -- + * AsyncTCPSocketAcceptInternal -- * * The meat of 'accept'. This function can be invoked either via a * poll callback or blocking. We call accept to get the new socket fd, * create a new asock, and call the newFn callback previously supplied - * by the call to AsyncSocket_Listen. + * by the call to AsyncTCPSocket_Listen. * * Results: * ASOCKERR_SUCCESS if everything works, else an error code. @@ -3557,24 +3491,23 @@ exit: */ static int -AsyncSocketAcceptInternal(AsyncSocket *s) +AsyncTCPSocketAcceptInternal(AsyncTCPSocket *s) // IN { - AsyncSocket *newsock; + AsyncTCPSocket *newsock; int sysErr; int fd; struct sockaddr_storage remoteAddr; socklen_t remoteAddrLen = sizeof remoteAddr; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(AsyncSocketIsLocked(s)); - ASSERT(s->state == AsyncSocketListening); + ASSERT(AsyncTCPSocketIsLocked(s)); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketListening); if ((fd = accept(s->fd, (struct sockaddr *)&remoteAddr, &remoteAddrLen)) == -1) { sysErr = ASOCK_LASTERROR(); s->genericErrno = sysErr; if (sysErr == ASOCK_EWOULDBLOCK) { - ASOCKWARN(s, ("spurious accept notification\n")); + TCPSOCKWARN(s, ("spurious accept notification\n")); return ASOCKERR_GENERIC; #ifndef _WIN32 @@ -3587,12 +3520,12 @@ AsyncSocketAcceptInternal(AsyncSocket *s) */ } else if (sysErr == ECONNABORTED) { - ASOCKLG0(s, ("accept: new connection was aborted\n")); + TCPSOCKLG0(s, ("accept: new connection was aborted\n")); return ASOCKERR_GENERIC; #endif } else { - ASOCKWARN(s, ("accept failed on fd %d, error %d: %s\n", + TCPSOCKWARN(s, ("accept failed on fd %d, error %d: %s\n", s->fd, sysErr, Err_Errno2String(sysErr))); return ASOCKERR_ACCEPT; @@ -3600,7 +3533,7 @@ AsyncSocketAcceptInternal(AsyncSocket *s) } if (remoteAddr.ss_family == AF_INET6 && - AsyncSocketOSVersionSupportsV4Mapped()) { + AsyncTCPSocketOSVersionSupportsV4Mapped()) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&remoteAddr; /* @@ -3610,15 +3543,16 @@ AsyncSocketAcceptInternal(AsyncSocket *s) */ if (IN6_IS_ADDR_V4MAPPED(&(addr6->sin6_addr))) { - ASOCKWARN(s, ("accept rejected on fd %d due to a IPv4-mapped IPv6 " - "remote connection address.\n", s->fd)); + TCPSOCKWARN(s, + ("accept rejected on fd %d due to a IPv4-mapped IPv6 " + "remote connection address.\n", s->fd)); SSLGeneric_close(fd); return ASOCKERR_ACCEPT; } } - newsock = AsyncSocket_AttachToFd(fd, &s->pollParams, NULL); + newsock = AsyncTCPSocketAttachToFd(fd, AsyncTCPSocketPollParams(s), NULL); if (!newsock) { SSLGeneric_close(fd); @@ -3627,12 +3561,14 @@ AsyncSocketAcceptInternal(AsyncSocket *s) newsock->remoteAddr = remoteAddr; newsock->remoteAddrLen = remoteAddrLen; - newsock->state = AsyncSocketConnected; - newsock->vt = s->vt; + AsyncTCPSocketSetState(newsock, AsyncSocketConnected); + newsock->internalRecvFn = s->internalRecvFn; + newsock->internalSendFn = s->internalSendFn; - ASSERT(s->vt); - ASSERT(s->vt->dispatchConnect); - s->vt->dispatchConnect(s, newsock); + /* + * Fire the connect callback: + */ + s->connectFn(BaseSocket(newsock), s->clientData); return ASOCKERR_SUCCESS; } @@ -3641,7 +3577,7 @@ AsyncSocketAcceptInternal(AsyncSocket *s) /* *---------------------------------------------------------------------------- * - * AsyncSocketConnectInternal -- + * AsyncTCPSocketConnectInternal -- * * The meat of connect. This function is invoked either via a poll * callback or the blocking API and verifies that connect() succeeded @@ -3658,13 +3594,12 @@ AsyncSocketAcceptInternal(AsyncSocket *s) */ static int -AsyncSocketConnectInternal(AsyncSocket *s) +AsyncTCPSocketConnectInternal(AsyncTCPSocket *s) // IN { int optval = 0, optlen = sizeof optval, sysErr; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(AsyncSocketIsLocked(s)); - ASSERT(s->state == AsyncSocketConnecting); + ASSERT(AsyncTCPSocketIsLocked(s)); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnecting); /* Remove when bug 859728 is fixed */ if (vmx86_server && s->remoteAddr.ss_family == AF_UNIX) { @@ -3683,7 +3618,7 @@ AsyncSocketConnectInternal(AsyncSocket *s) if (optval != 0) { s->genericErrno = optval; - ASOCKLOG(1, s, ("connection SO_ERROR: %s\n", Err_Errno2String(optval))); + TCPSOCKLOG(1, s, ("connection SO_ERROR: %s\n", Err_Errno2String(optval))); return ASOCKERR_GENERIC; } @@ -3700,8 +3635,8 @@ AsyncSocketConnectInternal(AsyncSocket *s) } done: - s->state = AsyncSocketConnected; - s->connectFn(s, s->clientData); + AsyncTCPSocketSetState(s, AsyncSocketConnected); + s->connectFn(BaseSocket(s), s->clientData); return ASOCKERR_SUCCESS; } @@ -3710,7 +3645,7 @@ done: /* *---------------------------------------------------------------------------- * - * AsyncSocketGetGenericErrno -- + * AsyncTCPSocketGetGenericErrno -- * * Used when an ASOCKERR_GENERIC is returned due to a system error. * The errno that was returned by the system is stored in the asock @@ -3728,19 +3663,19 @@ done: *---------------------------------------------------------------------------- */ -int -AsyncSocketGetGenericErrno(AsyncSocket *s) // IN: +static int +AsyncTCPSocketGetGenericErrno(AsyncSocket *base) // IN: { - ASSERT(s); - - return s->genericErrno; + AsyncTCPSocket *asock = TCPSocket(base); + ASSERT(asock); + return asock->genericErrno; } /* *---------------------------------------------------------------------------- * - * AsyncSocket_WaitForConnection -- + * AsyncTCPSocketWaitForConnection -- * * Spins a socket currently listening or connecting until the * connection completes or the allowed time elapses. @@ -3754,37 +3689,31 @@ AsyncSocketGetGenericErrno(AsyncSocket *s) // IN: *---------------------------------------------------------------------------- */ -int -AsyncSocket_WaitForConnection(AsyncSocket *s, // IN: - int timeoutMS) // IN: +static int +AsyncTCPSocketWaitForConnection(AsyncSocket *base, // IN: + int timeoutMS) // IN: { + AsyncTCPSocket *s = TCPSocket(base); Bool read = FALSE; int error; VmTimeType now, done; Bool removed = FALSE; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(s->asockType != ASYNCSOCKET_TYPE_PROXYSOCKET); - - AsyncSocketLock(s); + ASSERT(AsyncTCPSocketIsLocked(s)); - if (s->state == AsyncSocketConnected) { - error = ASOCKERR_SUCCESS; - AsyncSocketUnlock(s); - goto out; + if (AsyncTCPSocketGetState(s) == AsyncSocketConnected) { + return ASOCKERR_SUCCESS; } - if (s->state != AsyncSocketListening && - s->state != AsyncSocketConnecting) { - error = ASOCKERR_GENERIC; - AsyncSocketUnlock(s); - goto out; + if (AsyncTCPSocketGetState(s) != AsyncSocketListening && + AsyncTCPSocketGetState(s) != AsyncSocketConnecting) { + return ASOCKERR_GENERIC; } - read = s->state == AsyncSocketListening; + read = AsyncTCPSocketGetState(s) == AsyncSocketListening; /* - * For listening sockets, unregister AsyncSocketAcceptCallback before + * For listening sockets, unregister AsyncTCPSocketAcceptCallback before * starting polling and re-register before returning. * * ConnectCallback() is either registered as a device or rtime callback @@ -3794,53 +3723,48 @@ AsyncSocket_WaitForConnection(AsyncSocket *s, // IN: if (read) { if (s->fd == -1) { if (s->listenAsock4) { - AsyncSocketLock(s->listenAsock4); - AsyncSocketCancelListenCbSocket(s->listenAsock4); - AsyncSocketUnlock(s->listenAsock4); + ASSERT(AsyncTCPSocketIsLocked(s->listenAsock4)); + AsyncTCPSocketCancelListenCb(s->listenAsock4); } if (s->listenAsock6) { - AsyncSocketLock(s->listenAsock6); - AsyncSocketCancelListenCbSocket(s->listenAsock6); - AsyncSocketUnlock(s->listenAsock6); + ASSERT(AsyncTCPSocketIsLocked(s->listenAsock6)); + AsyncTCPSocketCancelListenCb(s->listenAsock6); } } else { - AsyncSocketCancelListenCbSocket(s); + AsyncTCPSocketCancelListenCb(s); } removed = TRUE; } else { - removed = AsyncSocketPollRemove(s, TRUE, POLL_FLAG_WRITE, - AsyncSocketConnectCallback) - || AsyncSocketPollRemove(s, FALSE, 0, AsyncSocketConnectCallback); + removed = (AsyncTCPSocketPollRemove(s, TRUE, POLL_FLAG_WRITE, + AsyncTCPSocketConnectCallback) || + AsyncTCPSocketPollRemove(s, FALSE, 0, + AsyncTCPSocketConnectCallback)); ASSERT(removed); if (s->internalConnectFn) { - removed = AsyncSocketPollRemove(s, FALSE, POLL_FLAG_PERIODIC, - AsyncSocketConnectErrorCheck); + removed = AsyncTCPSocketPollRemove(s, FALSE, POLL_FLAG_PERIODIC, + AsyncTCPSocketConnectErrorCheck); ASSERT(removed); s->internalConnectFn = NULL; } } - AsyncSocketUnlock(s); - now = Hostinfo_SystemTimerUS() / 1000; done = now + timeoutMS; do { - AsyncSocket *asock = NULL; + AsyncTCPSocket *asock = NULL; - if ((error = AsyncSocketPoll(s, read, - done - now, &asock)) != ASOCKERR_SUCCESS) { + error = AsyncTCPSocketPoll(s, read, done - now, &asock); + if (error != ASOCKERR_SUCCESS) { goto out; } - AsyncSocketLock(asock); - now = Hostinfo_SystemTimerUS() / 1000; if (read) { - if (AsyncSocketAcceptInternal(asock) != ASOCKERR_SUCCESS) { - ASOCKLG0(s, ("wait for connection: accept failed\n")); + if (AsyncTCPSocketAcceptInternal(asock) != ASOCKERR_SUCCESS) { + TCPSOCKLG0(s, ("wait for connection: accept failed\n")); /* * Just fall through, we'll loop and try again as long as we still @@ -3849,16 +3773,12 @@ AsyncSocket_WaitForConnection(AsyncSocket *s, // IN: } else { error = ASOCKERR_SUCCESS; - AsyncSocketUnlock(asock); goto out; } } else { - error = AsyncSocketConnectInternal(asock); - AsyncSocketUnlock(asock); + error = AsyncTCPSocketConnectInternal(asock); goto out; } - - AsyncSocketUnlock(asock); } while ((now < done && timeoutMS > 0) || (timeoutMS < 0)); error = ASOCKERR_TIMEOUT; @@ -3866,27 +3786,23 @@ AsyncSocket_WaitForConnection(AsyncSocket *s, // IN: out: if (read && removed) { if (s->fd == -1) { - if (s->listenAsock4 && s->listenAsock4->state != AsyncSocketClosed) { - AsyncSocketLock(s->listenAsock4); - if (!AsyncSocketAddListenCbSocket(s->listenAsock4)) { + if (s->listenAsock4 && + AsyncTCPSocketGetState(s->listenAsock4) != AsyncSocketClosed) { + if (!AsyncTCPSocketAddListenCb(s->listenAsock4)) { error = ASOCKERR_POLL; } - AsyncSocketUnlock(s->listenAsock4); } - if (s->listenAsock6 && s->listenAsock6->state != AsyncSocketClosed) { - AsyncSocketLock(s->listenAsock6); - if (!AsyncSocketAddListenCbSocket(s->listenAsock6)) { + if (s->listenAsock6 && + AsyncTCPSocketGetState(s->listenAsock6) != AsyncSocketClosed) { + if (!AsyncTCPSocketAddListenCb(s->listenAsock6)) { error = ASOCKERR_POLL; } - AsyncSocketUnlock(s->listenAsock6); } - } else if (s->state != AsyncSocketClosed) { - AsyncSocketLock(s); - if (!AsyncSocketAddListenCbSocket(s)) { + } else if (AsyncTCPSocketGetState(s) != AsyncSocketClosed) { + if (!AsyncTCPSocketAddListenCb(s)) { error = ASOCKERR_POLL; } - AsyncSocketUnlock(s); } } @@ -3897,7 +3813,7 @@ out: /* *---------------------------------------------------------------------------- * - * AsyncSocket_DoOneMsg -- + * AsyncTCPSocketDoOneMsg -- * * Spins a socket until the specified amount of time has elapsed or * data has arrived / been sent. @@ -3912,21 +3828,17 @@ out: *---------------------------------------------------------------------------- */ -int -AsyncSocket_DoOneMsg(AsyncSocket *s, // IN - Bool read, // IN - int timeoutMS) // IN +static int +AsyncTCPSocketDoOneMsg(AsyncSocket *base, // IN + Bool read, // IN + int timeoutMS) // IN { + AsyncTCPSocket *s = TCPSocket(base); + AsyncTCPSocket *asock = NULL; int retVal; - AsyncSocket *asock = NULL; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(s->asockType != ASYNCSOCKET_TYPE_PROXYSOCKET); - - if (!s) { - Warning(ASOCKPREFIX "DoOneMsg called with invalid paramters.\n"); - return ASOCKERR_INVAL; - } + ASSERT(AsyncTCPSocketIsLocked(s)); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); if (read) { /* @@ -3938,65 +3850,61 @@ AsyncSocket_DoOneMsg(AsyncSocket *s, // IN * after reading the data. */ - AsyncSocketLock(s); - ASSERT(s->state == AsyncSocketConnected); ASSERT(s->recvCb); /* We are supposed to call someone... */ - AsyncSocketAddRef(s); - s->vt->cancelRecvCbInternal(s); + AsyncTCPSocketAddRef(s); + AsyncTCPSocketCancelRecvCb(s); s->recvCb = TRUE; /* We need to know if the callback cancel recv. */ s->inBlockingRecv++; - AsyncSocketUnlock(s); /* We may sleep in poll. */ - retVal = AsyncSocketPoll(s, read, timeoutMS, &asock); - AsyncSocketLock(s); + retVal = AsyncTCPSocketPoll(s, read, timeoutMS, &asock); s->inBlockingRecv--; if (retVal != ASOCKERR_SUCCESS) { if (retVal == ASOCKERR_GENERIC) { - ASOCKWARN(s, ("%s: failed to poll on the socket during read.\n", - __FUNCTION__)); + TCPSOCKWARN(s, ("%s: failed to poll on the socket during read.\n", + __FUNCTION__)); } } else { ASSERT(asock == s); - retVal = AsyncSocketFillRecvBuffer(s); + s->inDoOneMsg = TRUE; + retVal = AsyncTCPSocketFillRecvBuffer(s); + s->inDoOneMsg = FALSE; } /* - * If socket got closed in AsyncSocketFillRecvBuffer, we cannot add poll - * callback - AsyncSocket_Close() would remove it if we would not remove - * it above. + * If socket got closed in AsyncTCPSocketFillRecvBuffer, we + * cannot add poll callback - AsyncSocket_Close() would remove + * it if we would not remove it above. */ - if (s->state != AsyncSocketClosed && s->recvCb) { - ASSERT(s->refCount > 1); /* We should not be last user of socket. */ - ASSERT(s->state == AsyncSocketConnected); + if (AsyncTCPSocketGetState(s) != AsyncSocketClosed && s->recvCb) { + ASSERT(s->base.refCount > 1); /* We shouldn't be last user of socket. */ + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); /* - * If AsyncSocketPoll or AsyncSocketFillRecvBuffer fails, do not + * If AsyncTCPSocketPoll or AsyncTCPSocketFillRecvBuffer fails, do not * add the recv callback as it may never fire. */ s->recvCb = FALSE; /* For re-registering the poll callback. */ if (retVal == ASOCKERR_SUCCESS || retVal == ASOCKERR_TIMEOUT) { - retVal = s->vt->recvInternal(s, (uint8 *)s->recvBuf + s->recvPos, - s->recvLen - s->recvPos); + retVal = AsyncTCPSocketRegisterRecvCb(s); } if (retVal != ASOCKERR_SUCCESS) { - s->recvBuf = NULL; + s->base.recvBuf = NULL; } } - /* This may destroy socket s if it is in AsyncSocketClosed state now. */ - AsyncSocketRelease(s, TRUE); + AsyncTCPSocketRelease(s); } else { - if ((retVal = AsyncSocketPoll(s, read, timeoutMS, &asock)) != - ASOCKERR_SUCCESS) { + AsyncTCPSocketAddRef(s); + retVal = AsyncTCPSocketPoll(s, read, timeoutMS, &asock); + if (retVal != ASOCKERR_SUCCESS) { if (retVal == ASOCKERR_GENERIC) { - ASOCKWARN(s, ("%s: failed to poll on the socket during write.\n", - __FUNCTION__)); + TCPSOCKWARN(s, ("%s: failed to poll on the socket during write.\n", + __FUNCTION__)); } } else { ASSERT(asock == s); - AsyncSocketLock(s); - retVal = AsyncSocketWriteBuffers(s); - AsyncSocketUnlock(s); + retVal = AsyncTCPSocketWriteBuffers(s); } + AsyncTCPSocketRelease(s); } return retVal; @@ -4006,7 +3914,7 @@ AsyncSocket_DoOneMsg(AsyncSocket *s, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketFlush -- + * AsyncTCPSocketFlush -- * * Try to send any pending out buffers until we run out of buffers, or * the timeout expires. @@ -4021,26 +3929,25 @@ AsyncSocket_DoOneMsg(AsyncSocket *s, // IN *---------------------------------------------------------------------------- */ -int -AsyncSocketFlush(AsyncSocket *s, // IN - int timeoutMS) // IN +static int +AsyncTCPSocketFlush(AsyncSocket *base, // IN + int timeoutMS) // IN { + AsyncTCPSocket *s = TCPSocket(base); VmTimeType now, done; int retVal; - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - if (s == NULL) { Warning(ASOCKPREFIX "Flush called with invalid arguments!\n"); return ASOCKERR_INVAL; } - AsyncSocketLock(s); - AsyncSocketAddRef(s); + ASSERT(AsyncTCPSocketIsLocked(s)); + AsyncTCPSocketAddRef(s); - if (s->state != AsyncSocketConnected) { - ASOCKWARN(s, ("flush called but state is not connected!\n")); + if (AsyncTCPSocketGetState(s) != AsyncSocketConnected) { + TCPSOCKWARN(s, ("flush called but state is not connected!\n")); retVal = ASOCKERR_INVAL; goto outHaveLock; } @@ -4049,22 +3956,19 @@ AsyncSocketFlush(AsyncSocket *s, // IN done = now + timeoutMS; while (s->sendBufList) { - AsyncSocket *asock = NULL; - - AsyncSocketUnlock(s); /* We may sleep in poll. */ - retVal = AsyncSocketPoll(s, FALSE, done - now, &asock); - AsyncSocketLock(s); + AsyncTCPSocket *asock = NULL; + retVal = AsyncTCPSocketPoll(s, FALSE, done - now, &asock); if (retVal != ASOCKERR_SUCCESS) { - ASOCKWARN(s, ("flush failed\n")); + TCPSOCKWARN(s, ("flush failed\n")); goto outHaveLock; } ASSERT(asock == s); - if ((retVal = AsyncSocketWriteBuffers(s)) != ASOCKERR_SUCCESS) { + if ((retVal = AsyncTCPSocketWriteBuffers(s)) != ASOCKERR_SUCCESS) { goto outHaveLock; } - ASSERT(s->state == AsyncSocketConnected); + ASSERT(AsyncTCPSocketGetState(s) == AsyncSocketConnected); /* Setting timeoutMS to -1 means never timeout. */ if (timeoutMS >= 0) { @@ -4072,7 +3976,7 @@ AsyncSocketFlush(AsyncSocket *s, // IN /* Don't timeout if you've sent everything */ if (now > done && s->sendBufList) { - ASOCKWARN(s, ("flush timed out\n")); + TCPSOCKWARN(s, ("flush timed out\n")); retVal = ASOCKERR_TIMEOUT; goto outHaveLock; } @@ -4082,51 +3986,12 @@ AsyncSocketFlush(AsyncSocket *s, // IN retVal = ASOCKERR_SUCCESS; outHaveLock: - AsyncSocketRelease(s, TRUE); + AsyncTCPSocketRelease(s); return retVal; } -/* - *---------------------------------------------------------------------------- - * - * AsyncSocket_SetErrorFn -- - * - * Sets the error handling function for the asock. The error function - * is invoked automatically on I/O errors. Passing NULL as the error - * function restores the default behavior, which is to just destroy the - * AsyncSocket on any errors. - * - * Results: - * ASOCKERR_SUCCESS or ASOCKERR_INVAL. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -AsyncSocket_SetErrorFn(AsyncSocket *asock, // IN/OUT - AsyncSocketErrorFn errorFn, // IN - void *clientData) // IN -{ - if (!asock) { - Warning(ASOCKPREFIX "%s called with invalid arguments!\n", - __FUNCTION__); - - return ASOCKERR_INVAL; - } - AsyncSocketLock(asock); - asock->errorFn = errorFn; - asock->errorClientData = clientData; - AsyncSocketUnlock(asock); - - return ASOCKERR_SUCCESS; -} - - /* *---------------------------------------------------------------------------- * @@ -4143,16 +4008,16 @@ AsyncSocket_SetErrorFn(AsyncSocket *asock, // IN/OUT *---------------------------------------------------------------------------- */ -void -AsyncSocketCancelListenCbSocket(AsyncSocket *asock) // IN: +static void +AsyncTCPSocketCancelListenCb(AsyncTCPSocket *asock) // IN: { Bool removed; - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketIsLocked(asock)); - removed = AsyncSocketPollRemove(asock, TRUE, - POLL_FLAG_READ | POLL_FLAG_PERIODIC, - AsyncSocketAcceptCallback); + removed = AsyncTCPSocketPollRemove(asock, TRUE, + POLL_FLAG_READ | POLL_FLAG_PERIODIC, + AsyncTCPSocketAcceptCallback); ASSERT(removed); } @@ -4160,7 +4025,7 @@ AsyncSocketCancelListenCbSocket(AsyncSocket *asock) // IN: /* *---------------------------------------------------------------------------- * - * AsyncSocketAddListenCbSocket -- + * AsyncTCPSocketAddListenCb -- * * Socket specific code for adding callbacks for a listening socket. * @@ -4174,18 +4039,18 @@ AsyncSocketCancelListenCbSocket(AsyncSocket *asock) // IN: */ static Bool -AsyncSocketAddListenCbSocket(AsyncSocket *asock) // IN: +AsyncTCPSocketAddListenCb(AsyncTCPSocket *asock) // IN: { VMwareStatus pollStatus; - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketIsLocked(asock)); - pollStatus = AsyncSocketPollAdd(asock, TRUE, POLL_FLAG_READ | - POLL_FLAG_PERIODIC, - AsyncSocketAcceptCallback); + pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, + POLL_FLAG_READ | POLL_FLAG_PERIODIC, + AsyncTCPSocketAcceptCallback); if (pollStatus != VMWARE_STATUS_SUCCESS) { - ASOCKWARN(asock, ("failed to install listen accept callback!\n")); + TCPSOCKWARN(asock, ("failed to install listen accept callback!\n")); } return pollStatus == VMWARE_STATUS_SUCCESS; @@ -4195,7 +4060,7 @@ AsyncSocketAddListenCbSocket(AsyncSocket *asock) // IN: /* *---------------------------------------------------------------------------- * - * AsyncSocketCancelRecvCbSocket -- + * AsyncTCPSocketCancelRecvCb -- * * Socket specific code for canceling callbacks when a receive * request is being canceled. @@ -4209,22 +4074,23 @@ AsyncSocketAddListenCbSocket(AsyncSocket *asock) // IN: *---------------------------------------------------------------------------- */ -void -AsyncSocketCancelRecvCbSocket(AsyncSocket *asock) // IN: +static void +AsyncTCPSocketCancelRecvCb(AsyncTCPSocket *asock) // IN: { - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketIsLocked(asock)); if (asock->recvCbTimer) { - AsyncSocketPollRemove(asock, FALSE, 0, asock->vt->recvCallback); + AsyncTCPSocketPollRemove(asock, FALSE, 0, asock->internalRecvFn); asock->recvCbTimer = FALSE; } if (asock->recvCb) { Bool removed; - ASOCKLOG(1, asock, ("Removing poll recv callback while cancelling recv.\n")); - removed = AsyncSocketPollRemove(asock, TRUE, - POLL_FLAG_READ | POLL_FLAG_PERIODIC, - asock->vt->recvCallback); - VERIFY(removed || asock->pollParams.iPoll); + TCPSOCKLOG(1, asock, + ("Removing poll recv callback while cancelling recv.\n")); + removed = AsyncTCPSocketPollRemove(asock, TRUE, + POLL_FLAG_READ | POLL_FLAG_PERIODIC, + asock->internalRecvFn); + VERIFY(removed || AsyncTCPSocketPollParams(asock)->iPoll); asock->recvCb = FALSE; } } @@ -4233,10 +4099,18 @@ AsyncSocketCancelRecvCbSocket(AsyncSocket *asock) // IN: /* *---------------------------------------------------------------------------- * - * AsyncSocketCancelCbForCloseSocket -- + * AsyncTCPSocketCancelCbForClose -- + * + * Cancel future asynchronous send and recv by unregistering + * their Poll callbacks, and change the socket state to + * AsyncTCPSocketCBCancelled if the socket state is AsyncTCPSocketConnected. * - * Socket specific code for canceling callbacks when a socket is - * being closed. + * The function can be called in a send/recv error handler before + * actually closing the socket in a separate thread, to prevent other + * code calling AsyncTCPSocket_Send/Recv from re-registering the + * callbacks again. The next operation should be just AsyncSocket_Close(). + * This helps to avoid unnecessary send/recv callbacks before the + * socket is closed. * * Results: * None. @@ -4249,11 +4123,18 @@ AsyncSocketCancelRecvCbSocket(AsyncSocket *asock) // IN: *---------------------------------------------------------------------------- */ -void -AsyncSocketCancelCbForCloseSocket(AsyncSocket *asock) // IN: +static void +AsyncTCPSocketCancelCbForClose(AsyncSocket *base) // IN: { + AsyncTCPSocket *asock = TCPSocket(base); Bool removed; + ASSERT(AsyncTCPSocketIsLocked(asock)); + + if (AsyncTCPSocketGetState(asock) == AsyncSocketConnected) { + AsyncTCPSocketSetState(asock, AsyncSocketCBCancelled); + } + /* * Remove the read and write poll callbacks. * @@ -4276,26 +4157,29 @@ AsyncSocketCancelCbForCloseSocket(AsyncSocket *asock) // IN: * handler invoked. */ - ASSERT(!asock->recvBuf || asock->recvCb); + ASSERT(!asock->base.recvBuf || asock->base.recvFn); if (asock->recvCbTimer) { - AsyncSocketPollRemove(asock, FALSE, 0, asock->vt->recvCallback); + AsyncTCPSocketPollRemove(asock, FALSE, 0, asock->internalRecvFn); asock->recvCbTimer = FALSE; } if (asock->recvCb) { - ASOCKLOG(1, asock, ("recvCb is non-NULL, removing recv callback\n")); - removed = AsyncSocketPollRemove(asock, TRUE, - POLL_FLAG_READ | POLL_FLAG_PERIODIC, - asock->vt->recvCallback); + TCPSOCKLOG(1, asock, ("recvCb is non-NULL, removing recv callback\n")); + removed = AsyncTCPSocketPollRemove(asock, TRUE, + POLL_FLAG_READ | POLL_FLAG_PERIODIC, + asock->internalRecvFn); /* Callback might be temporarily removed in AsyncSocket_DoOneMsg. */ - ASSERT_NOT_TESTED(removed || asock->pollParams.iPoll); + ASSERT_NOT_TESTED(removed || + asock->inDoOneMsg || + AsyncTCPSocketPollParams(asock)->iPoll); asock->recvCb = FALSE; - asock->recvBuf = NULL; + asock->base.recvBuf = NULL; } if (asock->sendCb) { - ASOCKLOG(1, asock, ("sendBufList is non-NULL, removing send callback\n")); + TCPSOCKLOG(1, asock, + ("sendBufList is non-NULL, removing send callback\n")); /* * The send callback could be either a device or RTime callback, so @@ -4303,60 +4187,24 @@ AsyncSocketCancelCbForCloseSocket(AsyncSocket *asock) // IN: */ if (asock->sendCbTimer) { - removed = AsyncSocketPollRemove(asock, FALSE, 0, - asock->vt->sendCallback); + removed = AsyncTCPSocketPollRemove(asock, FALSE, 0, + asock->internalSendFn); } else { - removed = AsyncSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, - asock->vt->sendCallback); + removed = AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, + asock->internalSendFn); } - ASSERT(removed || asock->pollParams.iPoll); + ASSERT(removed || AsyncTCPSocketPollParams(asock)->iPoll); asock->sendCb = FALSE; asock->sendCbTimer = FALSE; } -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketCancelCbForCloseInt -- - * - * Cancel future asynchronous send and recv by unregistering - * their Poll callbacks, and change the socket state to - * AsyncSocketCBCancelled if the socket state is AsyncSocketConnected. - * - * The function can be called in a send/recv error handler before - * actually closing the socket in a separate thread, to prevent other - * code calling AsyncSocket_Send/Recv from re-registering the - * callbacks again. The next operation should be just AsyncSocket_Close(). - * This helps to avoid unnecessary send/recv callbacks before the - * socket is closed. - * - * Results: - * None. - * - * Side effects: - * Unregisters send/recv Poll callbacks, and fires the send - * triggers for any remaining output buffers. May also change - * the socket state. - * - *---------------------------------------------------------------------------- - */ - -static void -AsyncSocketCancelCbForCloseInt(AsyncSocket *asock) // IN: -{ - ASSERT(AsyncSocketIsLocked(asock)); - - if (asock->state == AsyncSocketConnected) { - asock->state = AsyncSocketCBCancelled; - } - - ASSERT(asock->vt); - ASSERT(asock->vt->cancelCbForCloseInternal); - asock->vt->cancelCbForCloseInternal(asock); - AsyncSocketAddRef(asock); + /* + * 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. @@ -4365,80 +4213,22 @@ AsyncSocketCancelCbForCloseInt(AsyncSocket *asock) // IN: SendBufList *cur = asock->sendBufList; int pos = asock->sendPos; - /* - * Free the encoded data if it exists. - */ - free(cur->encodedBuf); asock->sendBufList = asock->sendBufList->next; asock->sendPos = 0; if (cur->sendFn) { - cur->sendFn(cur->buf, pos, asock, cur->clientData); + cur->sendFn(cur->buf, pos, BaseSocket(asock), cur->clientData); } free(cur); } - AsyncSocketRelease(asock, FALSE); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketCancelCbForClose -- - * - * This is the external version of AsyncSocketCancelCbForCloseInt(). It - * takes care of acquiring any necessary lock before calling the internal - * function. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -AsyncSocketCancelCbForClose(AsyncSocket *asock) // IN: -{ - AsyncSocketLock(asock); - AsyncSocketCancelCbForCloseInt(asock); - AsyncSocketUnlock(asock); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketCloseSocket -- - * - * AsyncSocket destructor for SSL sockets. - * - * Results: - * None. - * - * Side effects: - * Closes the socket fd. - * - *---------------------------------------------------------------------------- - */ - -void -AsyncSocketCloseSocket(AsyncSocket *asock) // IN -{ - SSL_Shutdown(asock->sslSock); - - if (asock->passFd.fd != -1) { - SSLGeneric_close(asock->passFd.fd); - } + AsyncTCPSocketRelease(asock); } /* *---------------------------------------------------------------------------- * - * AsyncSocketCancelCbForConnectingCloseSocket -- + * AsyncTCPSocketCancelCbForConnectingClose -- * * Cancels outstanding connect requests for a socket that is going * away. @@ -4452,19 +4242,20 @@ AsyncSocketCloseSocket(AsyncSocket *asock) // IN *---------------------------------------------------------------------------- */ -Bool -AsyncSocketCancelCbForConnectingCloseSocket(AsyncSocket *asock) // IN +static Bool +AsyncTCPSocketCancelCbForConnectingClose(AsyncTCPSocket *asock) // IN { - return AsyncSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, - AsyncSocketConnectCallback) - || AsyncSocketPollRemove(asock, FALSE, 0, AsyncSocketConnectCallback); + return (AsyncTCPSocketPollRemove(asock, TRUE, POLL_FLAG_WRITE, + AsyncTCPSocketConnectCallback) || + AsyncTCPSocketPollRemove(asock, FALSE, 0, + AsyncTCPSocketConnectCallback)); } /* *---------------------------------------------------------------------------- * - * AsyncSocket_SetCloseOptions -- + * AsyncTCPSocketSetCloseOptions -- * * Enables optional behavior for AsyncSocket_Close(): * @@ -4485,26 +4276,24 @@ AsyncSocketCancelCbForConnectingCloseSocket(AsyncSocket *asock) // IN *---------------------------------------------------------------------------- */ -void -AsyncSocket_SetCloseOptions(AsyncSocket *asock, // IN - int flushEnabledMaxWaitMsec, // IN - AsyncSocketCloseCb closeCb) // IN +static void +AsyncTCPSocketSetCloseOptions(AsyncSocket *base, // IN + int flushEnabledMaxWaitMsec, // IN + AsyncSocketCloseFn closeCb) // IN { - if (!asock) { - Warning("%s() called with NULL asock!\n", __FUNCTION__); - return; - } + AsyncTCPSocket *asock = TCPSocket(base); asock->flushEnabledMaxWaitMsec = flushEnabledMaxWaitMsec; asock->closeCb = closeCb; + VERIFY(closeCb == NULL); } /* *---------------------------------------------------------------------------- * - * AsyncSocketClose -- + * AsyncTCPSocketClose -- * - * AsyncSocket destructor. The destructor should be safe to call at any + * AsyncTCPSocket destructor. The destructor should be safe to call at any * time. It's invoked automatically for I/O errors on slots that have no * error handler set, and should be called manually by the error handler * as necessary. It could also be called as part of the normal program @@ -4520,28 +4309,25 @@ AsyncSocket_SetCloseOptions(AsyncSocket *asock, // IN *---------------------------------------------------------------------------- */ -int -AsyncSocketClose(AsyncSocket *asock) // IN +static int +AsyncTCPSocketClose(AsyncSocket *base) // IN { + AsyncTCPSocket *asock = TCPSocket(base); Bool isListener = TRUE; - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); - if (asock->state == AsyncSocketClosed) { + if (AsyncTCPSocketGetState(asock) == AsyncSocketClosed) { Warning("%s() called on already closed asock!\n", __FUNCTION__); - AsyncSocketUnlock(asock); - return ASOCKERR_CLOSED; } if (asock->listenAsock4 || asock->listenAsock6) { - ASSERT(asock->refCount == 1); - if (asock->listenAsock4) { - AsyncSocket_Close(asock->listenAsock4); + AsyncSocket_Close(BaseSocket(asock->listenAsock4)); } if (asock->listenAsock6) { - AsyncSocket_Close(asock->listenAsock6); + AsyncSocket_Close(BaseSocket(asock->listenAsock6)); } } else { Bool removed; @@ -4549,14 +4335,16 @@ AsyncSocketClose(AsyncSocket *asock) // IN isListener = FALSE; - /* Flush output if requested via AsyncSocket_SetCloseOptions(). */ + /* Flush output if requested via AsyncTCPSocket_SetCloseOptions(). */ if (asock->flushEnabledMaxWaitMsec && - asock->state == AsyncSocketConnected && - !asock->errorSeen) { - int ret = AsyncSocket_Flush(asock, asock->flushEnabledMaxWaitMsec); + AsyncTCPSocketGetState(asock) == AsyncSocketConnected && + !asock->base.errorSeen) { + int ret = AsyncTCPSocketFlush(BaseSocket(asock), + asock->flushEnabledMaxWaitMsec); if (ret != ASOCKERR_SUCCESS) { - ASOCKWARN(asock, ("AsyncSocket_Flush failed: %s. Closing now.\n", - AsyncSocket_Err2String(ret))); + TCPSOCKWARN(asock, + ("AsyncTCPSocket_Flush failed: %s. Closing now.\n", + AsyncSocket_Err2String(ret))); } } @@ -4565,38 +4353,34 @@ AsyncSocketClose(AsyncSocket *asock) // IN * right thing accordingly */ - ASOCKLOG(1, asock, ("closing socket\n")); - oldState = asock->state; - asock->state = AsyncSocketClosed; - - ASSERT(asock->vt); + TCPSOCKLOG(1, asock, ("closing socket\n")); + oldState = AsyncTCPSocketGetState(asock); + AsyncTCPSocketSetState(asock, AsyncSocketClosed); switch(oldState) { case AsyncSocketListening: - ASOCKLOG(1, asock, ("old state was listening, removing accept " - "callback\n")); - ASSERT(asock->vt->cancelListenCbInternal); - asock->vt->cancelListenCbInternal(asock); + TCPSOCKLOG(1, asock, ("old state was listening, removing accept " + "callback\n")); + AsyncTCPSocketCancelListenCb(asock); break; case AsyncSocketConnecting: - ASOCKLOG(1, asock, ("old state was connecting, removing connect " - "callback\n")); - ASSERT(asock->vt->cancelCbForConnectingCloseInternal); - removed = asock->vt->cancelCbForConnectingCloseInternal(asock); + TCPSOCKLOG(1, asock, ("old state was connecting, removing connect " + "callback\n")); + removed = AsyncTCPSocketCancelCbForConnectingClose(asock); if (!removed) { - ASOCKLOG(1, asock, ("connect callback is not present in the poll " - "list.\n")); + TCPSOCKLOG(1, asock, ("connect callback is not present in the poll " + "list.\n")); } break; case AsyncSocketConnected: - ASOCKLOG(1, asock, ("old state was connected\n")); - AsyncSocketCancelCbForCloseInt(asock); + TCPSOCKLOG(1, asock, ("old state was connected\n")); + AsyncTCPSocketCancelCbForClose(BaseSocket(asock)); break; case AsyncSocketCBCancelled: - ASOCKLOG(1, asock, ("old state was CB-cancelled\n")); + TCPSOCKLOG(1, asock, ("old state was CB-cancelled\n")); break; default: @@ -4604,30 +4388,34 @@ AsyncSocketClose(AsyncSocket *asock) // IN } if (asock->internalConnectFn) { - removed = AsyncSocketPollRemove(asock, FALSE, POLL_FLAG_PERIODIC, - AsyncSocketConnectErrorCheck); + removed = AsyncTCPSocketPollRemove(asock, FALSE, POLL_FLAG_PERIODIC, + AsyncTCPSocketConnectErrorCheck); ASSERT(removed); asock->internalConnectFn = NULL; } if (asock->sslConnectFn && asock->sslPollFlags > 0) { - removed = AsyncSocketPollRemove(asock, TRUE, asock->sslPollFlags, - AsyncSocketSslConnectCallback); + removed = AsyncTCPSocketPollRemove(asock, TRUE, asock->sslPollFlags, + AsyncTCPSocketSslConnectCallback); ASSERT(removed); } if (asock->sslAcceptFn && asock->sslPollFlags > 0) { - removed = AsyncSocketPollRemove(asock, TRUE, asock->sslPollFlags, - AsyncSocketSslAcceptCallback); + removed = AsyncTCPSocketPollRemove(asock, TRUE, asock->sslPollFlags, + AsyncTCPSocketSslAcceptCallback); ASSERT(removed); } asock->sslPollFlags = 0; - ASSERT(asock->vt->closeInternal); - asock->vt->closeInternal(asock); - } + /* + * Close the underlying SSL sockets. + */ + SSL_Shutdown(asock->sslSock); - AsyncSocketRelease(asock, TRUE); + if (asock->passFd.fd != -1) { + SSLGeneric_close(asock->passFd.fd); + } + } return ASOCKERR_SUCCESS; } @@ -4636,32 +4424,7 @@ AsyncSocketClose(AsyncSocket *asock) // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketGetState -- - * - * Returns the state of the provided asock or ASOCKERR_INVAL. Note that - * unless this is called from a callback function, the state should be - * treated as transient (except the state AsyncSocketClosed). - * - * Results: - * AsyncSocketState enum. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -AsyncSocketState -AsyncSocketGetState(AsyncSocket *asock) -{ - return (asock ? asock->state : ASOCKERR_INVAL); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketIsSendBufferFull -- + * AsyncTCPSocketIsSendBufferFull -- * * Indicate if socket send buffer is full. Note that unless this is * called from a callback function, the return value should be treated @@ -4678,118 +4441,22 @@ AsyncSocketGetState(AsyncSocket *asock) *---------------------------------------------------------------------------- */ -int -AsyncSocketIsSendBufferFull(AsyncSocket *asock) -{ - return (asock ? asock->sendBufFull : ASOCKERR_GENERIC); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocket_GetID -- - * - * Returns a unique identifier for the asock. - * - * Results: - * Integer id or ASOCKERR_INVAL. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -AsyncSocket_GetID(AsyncSocket *asock) -{ - return (asock ? asock->id : ASOCKERR_INVAL); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketSendInternal -- - * - * Internal send method for 'regular' socket connections, allocates & prepares - * a buffer and enqueues it. - * - * Results: - * ASOCKERR_SUCCESS if there are no errors. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -AsyncSocketSendInternal(AsyncSocket *asock, // IN - void *buf, // IN - int len, // IN - AsyncSocketSendFn sendFn, // IN - void *clientData, // IN - Bool *bufferListWasEmpty) // IN +static int +AsyncTCPSocketIsSendBufferFull(AsyncSocket *base) // IN { - SendBufList *newBuf; - ASSERT(bufferListWasEmpty); - - /* - * Allocate and initialize new send buffer entry - */ - - newBuf = Util_SafeCalloc(1, sizeof *newBuf); - newBuf->buf = buf; - newBuf->len = len; - newBuf->sendFn = sendFn; - newBuf->clientData = clientData; - - /* - * Append new send buffer to the tail of list. - */ - - *asock->sendBufTail = newBuf; - asock->sendBufTail = &(newBuf->next); - if (asock->sendBufList == newBuf) { - *bufferListWasEmpty = TRUE; - } - - return ASOCKERR_SUCCESS; + AsyncTCPSocket *asock = TCPSocket(base); + return asock->sendBufFull; } -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketDispatchConnect -- - * - * Simple dispatch to call the connect callback for the socket pair. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -void -AsyncSocketDispatchConnect(AsyncSocket *asock, - AsyncSocket *newsock) -{ - asock->connectFn(newsock, asock->clientData); -} /* *---------------------------------------------------------------------------- * - * AsyncSocketHasDataPendingSocket -- + * AsyncTCPSocketHasDataPending -- * - * Determine if the SSL socket has any pending/unread data. + * Determine if SSL has any pending/unread data. * * Results: * TRUE if this socket has pending data. @@ -4801,7 +4468,7 @@ AsyncSocketDispatchConnect(AsyncSocket *asock, */ static Bool -AsyncSocketHasDataPendingSocket(AsyncSocket *asock) // IN +AsyncTCPSocketHasDataPending(AsyncTCPSocket *asock) // IN: { return SSL_Pending(asock->sslSock); } @@ -4810,33 +4477,7 @@ AsyncSocketHasDataPendingSocket(AsyncSocket *asock) // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketHasDataPending -- - * - * Determine if the SSL or WebSocket has any pending/unread data. - * - * Results: - * TRUE if this socket has pending data. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Bool -AsyncSocketHasDataPending(AsyncSocket *asock) // IN: -{ - ASSERT(asock->vt); - ASSERT(asock->vt->hasDataPending); - - return asock->vt->hasDataPending(asock); -} - - -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketMakeNonBlocking -- + * AsyncTCPSocketMakeNonBlocking -- * * Make the specified socket non-blocking if it isn't already. * @@ -4850,7 +4491,7 @@ AsyncSocketHasDataPending(AsyncSocket *asock) // IN: */ static int -AsyncSocketMakeNonBlocking(int fd) +AsyncTCPSocketMakeNonBlocking(int fd) // IN { #ifdef _WIN32 int retval; @@ -4885,40 +4526,6 @@ AsyncSocketMakeNonBlocking(int fd) } -/* - *---------------------------------------------------------------------------- - * - * AsyncSocketHandleError -- - * - * Internal error handling helper. Changes the socket's state to error, - * and calls the registered error handler or closes the socket. - * - * Results: - * None. - * - * Side effects: - * Lots. - * - *---------------------------------------------------------------------------- - */ - -void -AsyncSocketHandleError(AsyncSocket *asock, int asockErr) -{ - ASSERT(asock); - asock->errorSeen = TRUE; - if (asock->errorFn) { - ASOCKLOG(3, asock, ("firing error callback (%s)\n", - AsyncSocket_Err2String(asockErr))); - asock->errorFn(asockErr, asock, asock->errorClientData); - } else { - ASOCKLOG(3, asock, ("no error callback, closing socket (%s)\n", - AsyncSocket_Err2String(asockErr))); - AsyncSocket_Close(asock); - } -} - - /* *---------------------------------------------------------------------------- * @@ -4927,7 +4534,7 @@ AsyncSocketHandleError(AsyncSocket *asock, int asockErr) * Poll callback for listening fd waiting to complete an accept * operation. We call accept to get the new socket fd, create a new * asock, and call the newFn callback previously supplied by the call to - * AsyncSocket_Listen. + * AsyncTCPSocket_Listen. * * Results: * None. @@ -4939,37 +4546,36 @@ AsyncSocketHandleError(AsyncSocket *asock, int asockErr) */ static void -AsyncSocketAcceptCallback(void *clientData) +AsyncTCPSocketAcceptCallback(void *clientData) // IN { - AsyncSocket *asock = clientData; + AsyncTCPSocket *asock = clientData; int retval; ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(asock->pollParams.iPoll == NULL); - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketPollParams(asock)->iPoll == NULL); + ASSERT(AsyncTCPSocketIsLocked(asock)); - AsyncSocketAddRef(asock); - retval = AsyncSocketAcceptInternal(asock); + AsyncTCPSocketAddRef(asock); + retval = AsyncTCPSocketAcceptInternal(asock); /* - * See comment for return value of AsyncSocketAcceptInternal(). + * See comment for return value of AsyncTCPSocketAcceptInternal(). */ if (retval == ASOCKERR_ACCEPT) { - AsyncSocketHandleError(asock, retval); + AsyncTCPSocketHandleError(asock, retval); } - AsyncSocketRelease(asock, FALSE); + AsyncTCPSocketRelease(asock); } /* *---------------------------------------------------------------------------- * - * AsyncSocketConnectCallback -- + * AsyncTCPSocketConnectCallback -- * * Poll callback for connecting fd. Calls through to - * AsyncSocketConnectInternal to do the real work. + * AsyncTCPSocketConnectInternal to do the real work. * * Results: * None. @@ -4981,30 +4587,29 @@ AsyncSocketAcceptCallback(void *clientData) */ static void -AsyncSocketConnectCallback(void *clientData) +AsyncTCPSocketConnectCallback(void *clientData) // IN { - AsyncSocket *asock = clientData; + AsyncTCPSocket *asock = clientData; int retval; ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(asock->pollParams.iPoll == NULL); - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketPollParams(asock)->iPoll == NULL); + ASSERT(AsyncTCPSocketIsLocked(asock)); - AsyncSocketAddRef(asock); - retval = AsyncSocketConnectInternal(asock); + AsyncTCPSocketAddRef(asock); + retval = AsyncTCPSocketConnectInternal(asock); if (retval != ASOCKERR_SUCCESS) { ASSERT(retval == ASOCKERR_GENERIC); /* Only one we're expecting */ - AsyncSocketHandleError(asock, retval); + AsyncTCPSocketHandleError(asock, retval); } - AsyncSocketRelease(asock, FALSE); + AsyncTCPSocketRelease(asock); } /* *---------------------------------------------------------------------------- * - * AsyncSocketRecvCallback -- + * AsyncTCPSocketRecvCallback -- * * Poll callback for input waiting on the socket. We try to pull off the * remaining data requested by the current receive function. @@ -5018,36 +4623,35 @@ AsyncSocketConnectCallback(void *clientData) *---------------------------------------------------------------------------- */ -void -AsyncSocketRecvCallback(void *clientData) +static void +AsyncTCPSocketRecvCallback(void *clientData) // IN { - AsyncSocket *asock = clientData; + AsyncTCPSocket *asock = clientData; int error; ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketIsLocked(asock)); - AsyncSocketAddRef(asock); + AsyncTCPSocketAddRef(asock); - error = AsyncSocketFillRecvBuffer(asock); + error = AsyncTCPSocketFillRecvBuffer(asock); if (error == ASOCKERR_GENERIC || error == ASOCKERR_REMOTE_DISCONNECT) { - AsyncSocketHandleError(asock, error); + AsyncTCPSocketHandleError(asock, error); } - AsyncSocketRelease(asock, FALSE); + AsyncTCPSocketRelease(asock); } /* *---------------------------------------------------------------------------- * - * AsyncSocketIPollRecvCallback -- + * AsyncTCPSocketIPollRecvCallback -- * * 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. + * calling AsyncTCPSocketFillRecvBuffer to do the real work. * * Results: * None. @@ -5059,49 +4663,50 @@ AsyncSocketRecvCallback(void *clientData) */ static void -AsyncSocketIPollRecvCallback(void *clientData) // IN: +AsyncTCPSocketIPollRecvCallback(void *clientData) // IN: { #ifdef VMX86_TOOLS NOT_IMPLEMENTED(); #else - AsyncSocket *asock = clientData; + AsyncTCPSocket *asock = clientData; MXUserRecLock *lock; ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(asock->pollParams.lock == NULL || - !MXUser_IsCurThreadHoldingRecLock(asock->pollParams.lock)); + ASSERT(AsyncTCPSocketPollParams(asock)->lock == NULL || + !MXUser_IsCurThreadHoldingRecLock( + AsyncTCPSocketPollParams(asock)->lock)); - AsyncSocketLock(asock); + AsyncTCPSocketLock(asock); if (asock->recvCbTimer) { /* IVmdbPoll only has periodic callbacks. */ - AsyncSocketIPollRemove(asock, FALSE, 0, asock->vt->recvCallback); + AsyncTCPSocketIPollRemove(asock, FALSE, 0, asock->internalRecvFn); asock->recvCbTimer = FALSE; } asock->inIPollCb |= IN_IPOLL_RECV; - lock = asock->pollParams.lock; + lock = AsyncTCPSocketPollParams(asock)->lock; if (asock->recvCb && asock->inBlockingRecv == 0) { /* * There is no need to take a reference here -- the fact that this * callback is running means AsyncsocketIPollRemove would not release a * reference if it is called. */ - int error = AsyncSocketFillRecvBuffer(asock); + int error = AsyncTCPSocketFillRecvBuffer(asock); if (error == ASOCKERR_GENERIC || error == ASOCKERR_REMOTE_DISCONNECT) { - AsyncSocketHandleError(asock, error); + AsyncTCPSocketHandleError(asock, error); } } asock->inIPollCb &= ~IN_IPOLL_RECV; if (asock->recvCb) { - AsyncSocketUnlock(asock); + AsyncTCPSocketUnlock(asock); } else { /* * Callback has been unregistered. Per above, we need to release the * reference explicitly. */ - AsyncSocketRelease(asock, TRUE); + AsyncTCPSocketRelease(asock); + AsyncTCPSocketUnlock(asock); if (lock != NULL) { MXUser_DecRefRecLock(lock); } @@ -5113,7 +4718,7 @@ AsyncSocketIPollRecvCallback(void *clientData) // IN: /* *---------------------------------------------------------------------------- * - * AsyncSocketSendCallback -- + * AsyncTCPSocketSendCallback -- * * Poll callback for output socket buffer space available (socket is * writable). We iterate over all the remaining buffers in our queue, @@ -5129,22 +4734,22 @@ AsyncSocketIPollRecvCallback(void *clientData) // IN: *---------------------------------------------------------------------------- */ -void -AsyncSocketSendCallback(void *clientData) +static void +AsyncTCPSocketSendCallback(void *clientData) // IN { - AsyncSocket *s = clientData; + AsyncTCPSocket *s = clientData; int retval; ASSERT(s); - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - ASSERT(AsyncSocketIsLocked(s)); + ASSERT(AsyncTCPSocketIsLocked(s)); - AsyncSocketAddRef(s); - s->sendCb = FALSE; /* AsyncSocketSendCallback is never periodic */ + AsyncTCPSocketAddRef(s); + s->sendCb = FALSE; /* AsyncTCPSocketSendCallback is never periodic */ s->sendCbTimer = FALSE; - retval = AsyncSocketWriteBuffers(s); - if (retval != ASOCKERR_SUCCESS) { - AsyncSocketHandleError(s, retval); + retval = AsyncTCPSocketWriteBuffers(s); + if (retval != ASOCKERR_SUCCESS && + retval != ASOCKERR_CLOSED) { + AsyncTCPSocketHandleError(s, retval); } else if (s->sendBufList && !s->sendCb) { VMwareStatus pollStatus; @@ -5161,33 +4766,33 @@ AsyncSocketSendCallback(void *clientData) */ if (!s->sslConnected) { - pollStatus = AsyncSocketPollAdd(s, FALSE, 0, - s->vt->sendCallback, 100000); + pollStatus = AsyncTCPSocketPollAdd(s, FALSE, 0, + s->internalSendFn, 100000); VERIFY(pollStatus == VMWARE_STATUS_SUCCESS); s->sendCbTimer = TRUE; } else #endif { - pollStatus = AsyncSocketPollAdd(s, TRUE, POLL_FLAG_WRITE, - s->vt->sendCallback); + pollStatus = AsyncTCPSocketPollAdd(s, TRUE, POLL_FLAG_WRITE, + s->internalSendFn); VERIFY(pollStatus == VMWARE_STATUS_SUCCESS); } s->sendCb = TRUE; } - AsyncSocketRelease(s, FALSE); + AsyncTCPSocketRelease(s); } /* *---------------------------------------------------------------------------- * - * AsyncSocketIPollSendCallback -- + * AsyncTCPSocketIPollSendCallback -- * * 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. + * itself before calling AsyncTCPSocketSendCallback to do the real work. * * Results: * None. @@ -5199,20 +4804,19 @@ AsyncSocketSendCallback(void *clientData) */ static void -AsyncSocketIPollSendCallback(void *clientData) // IN: +AsyncTCPSocketIPollSendCallback(void *clientData) // IN: { #ifdef VMX86_TOOLS NOT_IMPLEMENTED(); #else - AsyncSocket *s = clientData; + AsyncTCPSocket *s = clientData; MXUserRecLock *lock; ASSERT(s); - ASSERT(s->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - AsyncSocketLock(s); + AsyncTCPSocketLock(s); s->inIPollCb |= IN_IPOLL_SEND; - lock = s->pollParams.lock; + lock = AsyncTCPSocketPollParams(s)->lock; if (s->sendCb) { /* * Unregister this callback as we want the non-periodic behavior. There @@ -5221,17 +4825,18 @@ AsyncSocketIPollSendCallback(void *clientData) // IN: * We would release that reference at the end. */ if (s->sendCbTimer) { - AsyncSocketIPollRemove(s, FALSE, 0, AsyncSocketIPollSendCallback); + AsyncTCPSocketIPollRemove(s, FALSE, 0, AsyncTCPSocketIPollSendCallback); } else { - AsyncSocketIPollRemove(s, TRUE, POLL_FLAG_WRITE, - AsyncSocketIPollSendCallback); + AsyncTCPSocketIPollRemove(s, TRUE, POLL_FLAG_WRITE, + AsyncTCPSocketIPollSendCallback); } - AsyncSocketSendCallback(s); + AsyncTCPSocketSendCallback(s); } s->inIPollCb &= ~IN_IPOLL_SEND; - AsyncSocketRelease(s, TRUE); + AsyncTCPSocketRelease(s); + AsyncTCPSocketUnlock(s); if (lock != NULL) { MXUser_DecRefRecLock(lock); } @@ -5242,80 +4847,7 @@ AsyncSocketIPollSendCallback(void *clientData) // IN: /* *----------------------------------------------------------------------------- * - * AsyncSocketAddRef -- - * - * Increments reference count on AsyncSocket struct. - * - * Results: - * New reference count. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -AsyncSocketAddRef(AsyncSocket *s) -{ - ASSERT(s && s->refCount > 0); - ASOCKLOG(1, s, ("%s (count now %d)\n", __FUNCTION__, s->refCount + 1)); - - return ++s->refCount; -} - - -/* - *----------------------------------------------------------------------------- - * - * AsyncSocketRelease -- - * - * Decrements reference count on AsyncSocket struct, freeing it when it - * reaches 0. If "unlock" is TRUE, releases the lock after decrementing - * the count. - * - * Results: - * New reference count; 0 if freed. - * - * Side effects: - * May free struct. - * - *----------------------------------------------------------------------------- - */ - -int -AsyncSocketRelease(AsyncSocket *s, // IN: - Bool unlock) // IN: release lock -{ - int count = --s->refCount; - - if (unlock) { - AsyncSocketUnlock(s); - } - if (0 == count) { - ASOCKLOG(1, s, ("Final release; freeing asock struct\n")); - - if (s->closeCb) { - s->closeCb(s); - } - - if (s->vt && s->vt->release) { - s->vt->release(s); - } - free(s); - - return 0; - } - ASOCKLOG(1, s, ("Release (count now %d)\n", count)); - - return count; -} - - -/* - *----------------------------------------------------------------------------- - * - * AsyncSocketPollAdd -- + * AsyncTCPSocketPollAdd -- * * Add a poll callback. Wrapper for Poll_Callback since we always call * it in one of two basic forms. @@ -5331,17 +4863,15 @@ AsyncSocketRelease(AsyncSocket *s, // IN: *----------------------------------------------------------------------------- */ -VMwareStatus -AsyncSocketPollAdd(AsyncSocket *asock, - Bool socket, - int flags, - PollerFunction callback, - ...) +static VMwareStatus +AsyncTCPSocketPollAdd(AsyncTCPSocket *asock, // IN + Bool socket, // IN + int flags, // IN + PollerFunction callback, // IN + ...) // IN { int type, info; - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - if (socket) { ASSERT(asock->fd != -1); type = POLL_DEVICE; @@ -5357,21 +4887,21 @@ AsyncSocketPollAdd(AsyncSocket *asock, va_end(marker); } - if (asock->pollParams.iPoll != NULL) { - return AsyncSocketIPollAdd(asock, socket, flags, callback, info); + if (AsyncTCPSocketPollParams(asock)->iPoll != NULL) { + return AsyncTCPSocketIPollAdd(asock, socket, flags, callback, info); } - return Poll_Callback(asock->pollParams.pollClass, - flags | asock->pollParams.flags, + return Poll_Callback(AsyncTCPSocketPollParams(asock)->pollClass, + flags | AsyncTCPSocketPollParams(asock)->flags, callback, asock, type, info, - asock->pollParams.lock); + AsyncTCPSocketPollParams(asock)->lock); } /* *----------------------------------------------------------------------------- * - * AsyncSocketPollRemove -- + * AsyncTCPSocketPollRemove -- * * Remove a poll callback. Wrapper for Poll_CallbackRemove since we * always call it in one of two basic forms. @@ -5385,18 +4915,16 @@ AsyncSocketPollAdd(AsyncSocket *asock, *----------------------------------------------------------------------------- */ -Bool -AsyncSocketPollRemove(AsyncSocket *asock, - Bool socket, - int flags, - PollerFunction callback) +static Bool +AsyncTCPSocketPollRemove(AsyncTCPSocket *asock, // IN + Bool socket, // IN + int flags, // IN + PollerFunction callback) // IN { int type; - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); - - if (asock->pollParams.iPoll != NULL) { - return AsyncSocketIPollRemove(asock, socket, flags, callback); + if (AsyncTCPSocketPollParams(asock)->iPoll != NULL) { + return AsyncTCPSocketIPollRemove(asock, socket, flags, callback); } if (socket) { @@ -5407,8 +4935,8 @@ AsyncSocketPollRemove(AsyncSocket *asock, type = POLL_REALTIME; } - return Poll_CallbackRemove(asock->pollParams.pollClass, - flags | asock->pollParams.flags, + return Poll_CallbackRemove(AsyncTCPSocketPollParams(asock)->pollClass, + flags | AsyncTCPSocketPollParams(asock)->flags, callback, asock, type); } @@ -5416,7 +4944,7 @@ AsyncSocketPollRemove(AsyncSocket *asock, /* *----------------------------------------------------------------------------- * - * AsyncSocketIPollAdd -- + * AsyncTCPSocketIPollAdd -- * * Add a poll callback. Wrapper for IVmdbPoll.Register[Timer]. * @@ -5432,11 +4960,11 @@ AsyncSocketPollRemove(AsyncSocket *asock, */ static VMwareStatus -AsyncSocketIPollAdd(AsyncSocket *asock, - Bool socket, - int flags, - PollerFunction callback, - int info) +AsyncTCPSocketIPollAdd(AsyncTCPSocket *asock, // IN + Bool socket, // IN + int flags, // IN + PollerFunction callback, // IN + int info) // IN { #ifdef VMX86_TOOLS return VMWARE_STATUS_ERROR; @@ -5445,16 +4973,16 @@ AsyncSocketIPollAdd(AsyncSocket *asock, VmdbRet ret; IVmdbPoll *poll; - ASSERT(asock->pollParams.iPoll); - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketPollParams(asock)->iPoll); + ASSERT(AsyncTCPSocketIsLocked(asock)); /* Protect asyncsocket and lock from disappearing */ - AsyncSocketAddRef(asock); - if (asock->pollParams.lock != NULL) { - MXUser_IncRefRecLock(asock->pollParams.lock); + AsyncTCPSocketAddRef(asock); + if (AsyncTCPSocketPollParams(asock)->lock != NULL) { + MXUser_IncRefRecLock(AsyncTCPSocketPollParams(asock)->lock); } - poll = asock->pollParams.iPoll; + poll = AsyncTCPSocketPollParams(asock)->iPoll; if (socket) { int pollFlags = (flags & POLL_FLAG_READ) != 0 ? VMDB_PRF_READ @@ -5468,10 +4996,10 @@ AsyncSocketIPollAdd(AsyncSocket *asock, 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); + if (AsyncTCPSocketPollParams(asock)->lock != NULL) { + MXUser_DecRefRecLock(AsyncTCPSocketPollParams(asock)->lock); } - AsyncSocketRelease(asock, FALSE); + AsyncTCPSocketRelease(asock); status = VMWARE_STATUS_ERROR; } @@ -5483,7 +5011,7 @@ AsyncSocketIPollAdd(AsyncSocket *asock, /* *----------------------------------------------------------------------------- * - * AsyncSocketIPollRemove -- + * AsyncTCPSocketIPollRemove -- * * Remove a poll callback. Wrapper for IVmdbPoll.Unregister[Timer]. * @@ -5499,10 +5027,10 @@ AsyncSocketIPollAdd(AsyncSocket *asock, */ static Bool -AsyncSocketIPollRemove(AsyncSocket *asock, - Bool socket, - int flags, - PollerFunction callback) +AsyncTCPSocketIPollRemove(AsyncTCPSocket *asock, // IN + Bool socket, // IN + int flags, // IN + PollerFunction callback) // IN { #ifdef VMX86_TOOLS return FALSE; @@ -5510,10 +5038,10 @@ AsyncSocketIPollRemove(AsyncSocket *asock, IVmdbPoll *poll; Bool ret; - ASSERT(asock->pollParams.iPoll); - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketPollParams(asock)->iPoll); + ASSERT(AsyncTCPSocketIsLocked(asock)); - poll = asock->pollParams.iPoll; + poll = AsyncTCPSocketPollParams(asock)->iPoll; if (socket) { int pollFlags = (flags & POLL_FLAG_READ) != 0 ? VMDB_PRF_READ @@ -5526,17 +5054,17 @@ AsyncSocketIPollRemove(AsyncSocket *asock, if (ret && !((asock->inIPollCb & IN_IPOLL_RECV) != 0 && - callback == asock->vt->recvCallback) && + callback == asock->internalRecvFn) && !((asock->inIPollCb & IN_IPOLL_SEND) != 0 && - callback == asock->vt->sendCallback)) { - MXUserRecLock *lock = asock->pollParams.lock; + callback == asock->internalSendFn)) { + MXUserRecLock *lock = AsyncTCPSocketPollParams(asock)->lock; /* * As the callback has been unregistered and we are not currently in * the callback being removed, we can safely release the reference taken * when registering the callback. */ - AsyncSocketRelease(asock, FALSE); + AsyncTCPSocketRelease(asock); if (lock != NULL) { MXUser_DecRefRecLock(lock); } @@ -5550,74 +5078,54 @@ AsyncSocketIPollRemove(AsyncSocket *asock, /* *----------------------------------------------------------------------------- * - * AsyncSocketCancelRecv -- + * AsyncTCPSocketCancelRecv -- * * Call this function if you know what you are doing. This should be * called if you want to synchronously receive the outstanding data on * the socket. It removes the recv poll callback. It also returns number of * partially read bytes (if any). A partially read response may exist as - * AsyncSocketRecvCallback calls the recv callback only when all the data + * AsyncTCPSocketRecvCallback calls the recv callback only when all the data * has been received. * * Results: * ASOCKERR_SUCCESS or ASOCKERR_INVAL. * * Side effects: - * Subsequent client call to AsyncSocket_Recv can reinstate async behaviour. + * Subsequent client call to AsyncTCPSocket_Recv can reinstate async behaviour. * *----------------------------------------------------------------------------- */ -int -AsyncSocketCancelRecv(AsyncSocket *asock, // IN - int *partialRecvd, // OUT - void **recvBuf, // OUT - void **recvFn, // OUT - Bool cancelOnSend) // IN +static int +AsyncTCPSocketCancelRecv(AsyncSocket *base, // IN + int *partialRecvd, // OUT + void **recvBuf, // OUT + void **recvFn, // OUT + Bool cancelOnSend) // IN { - int retVal; + AsyncTCPSocket *asock = TCPSocket(base); - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); - if (asock->state != AsyncSocketConnected) { + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { Warning(ASOCKPREFIX "Failed to cancel request on disconnected socket!\n"); - retVal = ASOCKERR_INVAL; - goto outHaveLock; + return ASOCKERR_INVAL; } if (asock->inBlockingRecv) { Warning(ASOCKPREFIX "Cannot cancel request while a blocking recv is " "pending.\n"); - retVal = ASOCKERR_INVAL; - goto outHaveLock; + return ASOCKERR_INVAL; } if (!cancelOnSend && (asock->sendBufList || asock->sendCb)) { Warning(ASOCKPREFIX "Can't cancel request as socket has send operation " "pending.\n"); - retVal = ASOCKERR_INVAL; - goto outHaveLock; + return ASOCKERR_INVAL; } - ASSERT(asock->vt); - ASSERT(asock->vt->cancelRecvCbInternal); - asock->vt->cancelRecvCbInternal(asock); - - if (partialRecvd && asock->recvLen > 0) { - ASOCKLOG(1, asock, ("Partially read %d bytes out of %d bytes while " - "cancelling recv request.\n", asock->recvPos, asock->recvLen)); - *partialRecvd = asock->recvPos; - } - if (recvFn) { - *recvFn = asock->recvFn; - } - if (recvBuf) { - *recvBuf = asock->recvBuf; - } - asock->recvBuf = NULL; - asock->recvFn = NULL; - asock->recvPos = 0; - asock->recvLen = 0; + AsyncTCPSocketCancelRecvCb(asock); + AsyncSocketCancelRecv(BaseSocket(asock), partialRecvd, recvBuf, recvFn); if (asock->passFd.fd != -1) { SSLGeneric_close(asock->passFd.fd); @@ -5625,18 +5133,14 @@ AsyncSocketCancelRecv(AsyncSocket *asock, // IN } asock->passFd.expected = FALSE; - retVal = ASOCKERR_SUCCESS; - -outHaveLock: - AsyncSocketUnlock(asock); - return retVal; + return ASOCKERR_SUCCESS; } /* *----------------------------------------------------------------------------- * - * AsyncSocketGetReceivedFd -- + * AsyncTCPSocketGetReceivedFd -- * * Retrieve received file descriptor from socket. * @@ -5649,27 +5153,22 @@ outHaveLock: *----------------------------------------------------------------------------- */ -int -AsyncSocketGetReceivedFd(AsyncSocket *asock) // IN +static int +AsyncTCPSocketGetReceivedFd(AsyncSocket *base) // IN { + AsyncTCPSocket *asock = TCPSocket(base); int fd; - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); + ASSERT(AsyncTCPSocketIsLocked(asock)); - AsyncSocketLock(asock); - - if (asock->state != AsyncSocketConnected) { + if (AsyncTCPSocketGetState(asock) != AsyncSocketConnected) { Warning(ASOCKPREFIX "Failed to receive fd on disconnected socket!\n"); - AsyncSocketUnlock(asock); - return -1; } fd = asock->passFd.fd; asock->passFd.fd = -1; asock->passFd.expected = FALSE; - AsyncSocketUnlock(asock); - return fd; } @@ -5677,7 +5176,7 @@ AsyncSocketGetReceivedFd(AsyncSocket *asock) // IN /* *----------------------------------------------------------------------------- * - * AsyncSocketConnectSSL -- + * AsyncTCPSocketConnectSSL -- * * Initialize the socket's SSL object, by calling SSL_ConnectAndVerify. * NOTE: This call is blocking. @@ -5691,14 +5190,14 @@ AsyncSocketGetReceivedFd(AsyncSocket *asock) // IN *----------------------------------------------------------------------------- */ -Bool -AsyncSocketConnectSSL(AsyncSocket *asock, // IN - SSLVerifyParam *verifyParam, // IN/OPT - void *sslContext) // IN/OPT +static Bool +AsyncTCPSocketConnectSSL(AsyncSocket *base, // IN + SSLVerifyParam *verifyParam, // IN/OPT + void *sslContext) // IN/OPT { #ifndef USE_SSL_DIRECT + AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); if (sslContext == NULL) { sslContext = SSL_DefaultContext(); @@ -5715,7 +5214,7 @@ AsyncSocketConnectSSL(AsyncSocket *asock, // IN /* *----------------------------------------------------------------------------- * - * AsyncSocketAcceptSSL -- + * AsyncTCPSocketAcceptSSL -- * * Initialize the socket's SSL object, by calling SSL_Accept or * SSL_AcceptWithContext. @@ -5729,13 +5228,13 @@ AsyncSocketConnectSSL(AsyncSocket *asock, // IN *----------------------------------------------------------------------------- */ -Bool -AsyncSocketAcceptSSL(AsyncSocket *asock, // IN - void *sslCtx) // IN: optional +static Bool +AsyncTCPSocketAcceptSSL(AsyncSocket *base, // IN + void *sslCtx) // IN: optional { #ifndef USE_SSL_DIRECT + AsyncTCPSocket *asock = TCPSocket(base); ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); if (sslCtx) { return SSL_AcceptWithContext(asock->sslSock, sslCtx); @@ -5751,7 +5250,7 @@ AsyncSocketAcceptSSL(AsyncSocket *asock, // IN /* *---------------------------------------------------------------------------- * - * AsyncSocketSslConnectCallback -- + * AsyncTCPSocketSslConnectCallback -- * * Poll callback to redrive an outstanding ssl connect operation. * @@ -5765,43 +5264,43 @@ AsyncSocketAcceptSSL(AsyncSocket *asock, // IN */ static void -AsyncSocketSslConnectCallback(void *clientData) // IN +AsyncTCPSocketSslConnectCallback(void *clientData) // IN { #ifndef USE_SSL_DIRECT int sslOpCode; VMwareStatus pollStatus; - AsyncSocket *asock = clientData; + AsyncTCPSocket *asock = clientData; ASSERT(asock); - ASSERT(asock->pollParams.iPoll == NULL); - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketPollParams(asock)->iPoll == NULL); + ASSERT(AsyncTCPSocketIsLocked(asock)); - AsyncSocketAddRef(asock); + AsyncTCPSocketAddRef(asock); /* Only set if poll callback is registered */ asock->sslPollFlags = 0; sslOpCode = SSL_TryCompleteConnect(asock->sslSock); if (sslOpCode > 0) { - (*asock->sslConnectFn)(TRUE, asock, asock->clientData); + (*asock->sslConnectFn)(TRUE, BaseSocket(asock), asock->clientData); } else if (sslOpCode < 0) { - (*asock->sslConnectFn)(FALSE, asock, asock->clientData); + (*asock->sslConnectFn)(FALSE, BaseSocket(asock), asock->clientData); } else { asock->sslPollFlags = SSL_WantRead(asock->sslSock) ? POLL_FLAG_READ : POLL_FLAG_WRITE; /* register the poll callback to redrive the SSL connect */ - pollStatus = AsyncSocketPollAdd(asock, TRUE, asock->sslPollFlags, - AsyncSocketSslConnectCallback); + pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, asock->sslPollFlags, + AsyncTCPSocketSslConnectCallback); if (pollStatus != VMWARE_STATUS_SUCCESS) { - ASOCKWARN(asock, ("failed to reinstall ssl connect callback!\n")); + TCPSOCKWARN(asock, ("failed to reinstall ssl connect callback!\n")); asock->sslPollFlags = 0; - (*asock->sslConnectFn)(FALSE, asock, asock->clientData); + (*asock->sslConnectFn)(FALSE, BaseSocket(asock), asock->clientData); } } - AsyncSocketRelease(asock, FALSE); + AsyncTCPSocketRelease(asock); #else NOT_IMPLEMENTED(); #endif @@ -5811,7 +5310,7 @@ AsyncSocketSslConnectCallback(void *clientData) // IN /* *----------------------------------------------------------------------------- * - * AsyncSocketStartSslConnect -- + * AsyncTCPSocketStartSslConnect -- * * Start an asynchronous SSL connect operation. * @@ -5834,42 +5333,39 @@ AsyncSocketSslConnectCallback(void *clientData) // IN *----------------------------------------------------------------------------- */ -void -AsyncSocketStartSslConnect(AsyncSocket *asock, // IN - SSLVerifyParam *verifyParam, // IN/OPT - void *sslCtx, // IN - AsyncSocketSslConnectFn sslConnectFn, // IN - void *clientData) // IN +static void +AsyncTCPSocketStartSslConnect(AsyncSocket *base, // IN + SSLVerifyParam *verifyParam, // IN/OPT + void *sslCtx, // IN + AsyncSocketSslConnectFn sslConnectFn, // IN + void *clientData) // IN { #ifndef USE_SSL_DIRECT + AsyncTCPSocket *asock = TCPSocket(base); Bool ok; ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); ASSERT(sslConnectFn); - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); if (asock->sslConnectFn || asock->sslAcceptFn) { - ASOCKWARN(asock, ("An SSL operation was already initiated.\n")); - goto done; + TCPSOCKWARN(asock, ("An SSL operation was already initiated.\n")); + return; } ok = SSL_SetupConnectAndVerifyWithContext(asock->sslSock, verifyParam, sslCtx); if (!ok) { /* Something went wrong already */ - (*sslConnectFn)(FALSE, asock, clientData); - goto done; + (*sslConnectFn)(FALSE, BaseSocket(asock), clientData); + return; } asock->sslConnectFn = sslConnectFn; asock->clientData = clientData; - AsyncSocketSslConnectCallback(asock); - -done: - AsyncSocketUnlock(asock); + AsyncTCPSocketSslConnectCallback(asock); #else NOT_IMPLEMENTED(); #endif @@ -5879,7 +5375,7 @@ done: /* *---------------------------------------------------------------------------- * - * AsyncSocketSslAcceptCallback -- + * AsyncTCPSocketSslAcceptCallback -- * * Poll callback for redrive an outstanding ssl accept operation * @@ -5893,49 +5389,49 @@ done: */ static void -AsyncSocketSslAcceptCallback(void *clientData) +AsyncTCPSocketSslAcceptCallback(void *clientData) // IN { int sslOpCode; - AsyncSocket *asock = clientData; + AsyncTCPSocket *asock = clientData; VMwareStatus pollStatus; ASSERT(asock); - ASSERT(asock->pollParams.iPoll == NULL); - ASSERT(AsyncSocketIsLocked(asock)); + ASSERT(AsyncTCPSocketPollParams(asock)->iPoll == NULL); + ASSERT(AsyncTCPSocketIsLocked(asock)); - AsyncSocketAddRef(asock); + AsyncTCPSocketAddRef(asock); /* Only set if poll callback is registered */ asock->sslPollFlags = 0; sslOpCode = SSL_TryCompleteAccept(asock->sslSock); if (sslOpCode > 0) { - (*asock->sslAcceptFn)(TRUE, asock, asock->clientData); + (*asock->sslAcceptFn)(TRUE, BaseSocket(asock), asock->clientData); } else if (sslOpCode < 0) { - (*asock->sslAcceptFn)(FALSE, asock, asock->clientData); + (*asock->sslAcceptFn)(FALSE, BaseSocket(asock), asock->clientData); } else { asock->sslPollFlags = SSL_WantRead(asock->sslSock) ? POLL_FLAG_READ : POLL_FLAG_WRITE; /* register the poll callback to redrive the SSL accept */ - pollStatus = AsyncSocketPollAdd(asock, TRUE, asock->sslPollFlags, - AsyncSocketSslAcceptCallback); + pollStatus = AsyncTCPSocketPollAdd(asock, TRUE, asock->sslPollFlags, + AsyncTCPSocketSslAcceptCallback); if (pollStatus != VMWARE_STATUS_SUCCESS) { - ASOCKWARN(asock, ("failed to reinstall ssl accept callback!\n")); + TCPSOCKWARN(asock, ("failed to reinstall ssl accept callback!\n")); asock->sslPollFlags = 0; - (*asock->sslAcceptFn)(FALSE, asock, asock->clientData); + (*asock->sslAcceptFn)(FALSE, BaseSocket(asock), asock->clientData); } } - AsyncSocketRelease(asock, FALSE); + AsyncTCPSocketRelease(asock); } /* *----------------------------------------------------------------------------- * - * AsyncSocketStartSslAccept -- + * AsyncTCPSocketStartSslAccept -- * * Start an asynchronous SSL accept operation. * @@ -5961,46 +5457,43 @@ AsyncSocketSslAcceptCallback(void *clientData) *----------------------------------------------------------------------------- */ -void -AsyncSocketStartSslAccept(AsyncSocket *asock, // IN - void *sslCtx, // IN - AsyncSocketSslAcceptFn sslAcceptFn, // IN - void *clientData) // IN +static void +AsyncTCPSocketStartSslAccept(AsyncSocket *base, // IN + void *sslCtx, // IN + AsyncSocketSslAcceptFn sslAcceptFn, // IN + void *clientData) // IN { + AsyncTCPSocket *asock = TCPSocket(base); Bool ok; ASSERT(asock); - ASSERT(asock->asockType != ASYNCSOCKET_TYPE_NAMEDPIPE); ASSERT(sslAcceptFn); - AsyncSocketLock(asock); + ASSERT(AsyncTCPSocketIsLocked(asock)); if (asock->sslAcceptFn || asock->sslConnectFn) { - ASOCKWARN(asock, ("An SSL operation was already initiated.\n")); - goto done; + TCPSOCKWARN(asock, ("An SSL operation was already initiated.\n")); + return; } ok = SSL_SetupAcceptWithContext(asock->sslSock, sslCtx); if (!ok) { /* Something went wrong already */ - (*sslAcceptFn)(FALSE, asock, clientData); - goto done; + (*sslAcceptFn)(FALSE, BaseSocket(asock), clientData); + return; } asock->sslAcceptFn = sslAcceptFn; asock->clientData = clientData; - AsyncSocketSslAcceptCallback(asock); - -done: - AsyncSocketUnlock(asock); + AsyncTCPSocketSslAcceptCallback(asock); } /* *----------------------------------------------------------------------------- * - * AsyncSocketSetBufferSizes -- + * AsyncTCPSocketSetBufferSizes -- * * Set socket level recv/send buffer sizes if they are less than given sizes. * @@ -6014,11 +5507,12 @@ done: *----------------------------------------------------------------------------- */ -Bool -AsyncSocketSetBufferSizes(AsyncSocket *asock, // IN - int sendSz, // IN - int recvSz) // IN +static Bool +AsyncTCPSocketSetBufferSizes(AsyncSocket *base, // IN + int sendSz, // IN + int recvSz) // IN { + AsyncTCPSocket *asock = TCPSocket(base); int err; int buffSz; int len = sizeof buffSz; @@ -6074,11 +5568,11 @@ AsyncSocketSetBufferSizes(AsyncSocket *asock, // IN /* *----------------------------------------------------------------------------- * - * AsyncSocketSetSendLowLatencyMode -- + * AsyncTCPSocketSetSendLowLatencyMode -- * * Put the socket into a mode where we attempt to issue sends - * directly from within AsyncSocket_Send(). Ordinarily, we would - * set up a Poll callback from within AsyncSocket_Send(), which + * directly from within AsyncTCPSocket_Send(). Ordinarily, we would + * set up a Poll callback from within AsyncTCPSocket_Send(), which * introduces some non-zero latency to the send path. In * low-latency-send mode, that delay is potentially avoided. This * does introduce a behavioural change; the send completion @@ -6095,26 +5589,50 @@ AsyncSocketSetBufferSizes(AsyncSocket *asock, // IN *----------------------------------------------------------------------------- */ -void -AsyncSocketSetSendLowLatencyMode(AsyncSocket *asock, // IN - Bool enable) // IN +static void +AsyncTCPSocketSetSendLowLatencyMode(AsyncSocket *base, // IN + Bool enable) // IN { + AsyncTCPSocket *asock = TCPSocket(base); asock->sendLowLatency = enable; } +/* + *----------------------------------------------------------------------------- + * + * AsyncTCPSocketDestroy -- + * + * Free the AsyncTCPSocket struct and all of its child storage. + * + * Result + * None + * + * Side-effects + * Releases memory. + * + *----------------------------------------------------------------------------- + */ + +static void +AsyncTCPSocketDestroy(AsyncSocket *base) // IN/OUT +{ + free(base); +} + + #ifndef _WIN32 /* *----------------------------------------------------------------------------- * * AsyncSocket_ListenSocketUDS -- * - * Listens on the specified unix domain socket, and accepts new socket - * connections. Fires the connect callback with new AsyncSocket object for - * each connection. + * Listens on the specified unix domain socket, and accepts new + * socket connections. Fires the connect callback with new + * AsyncTCPSocket object for each connection. * * Results: - * New AsyncSocket in listening state or NULL on error + * New AsyncTCPSocket in listening state or NULL on error * * Side effects: * Creates new Unix domain socket, binds and listens. @@ -6130,6 +5648,7 @@ AsyncSocket_ListenSocketUDS(const char *pipeName, // IN int *outError) // OUT { struct sockaddr_un addr; + AsyncTCPSocket *asock; memset(&addr, 0, sizeof addr); addr.sun_family = AF_UNIX; @@ -6137,9 +5656,10 @@ AsyncSocket_ListenSocketUDS(const char *pipeName, // IN Log(ASOCKPREFIX "creating new socket listening on %s\n", pipeName); - return AsyncSocketListenImpl((struct sockaddr_storage *)&addr, - sizeof addr, - connectFn, clientData, pollParams, FALSE, - FALSE, NULL, NULL, outError); + asock = AsyncTCPSocketListenImpl((struct sockaddr_storage *)&addr, + sizeof addr, connectFn, clientData, + pollParams, outError); + + return BaseSocket(asock); } #endif diff --git a/open-vm-tools/lib/include/asyncsocket.h b/open-vm-tools/lib/include/asyncsocket.h index 0ae1c3a8b..2575c3359 100644 --- a/open-vm-tools/lib/include/asyncsocket.h +++ b/open-vm-tools/lib/include/asyncsocket.h @@ -49,10 +49,6 @@ #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" -#ifdef __APPLE__ -#include -#endif - #if defined(__cplusplus) extern "C" { #endif @@ -77,6 +73,30 @@ extern "C" { #define ASOCKERR_NETUNREACH 14 #define ASOCKERR_ADDRUNRESV 15 +/* + * Cross-platform codes for AsyncSocket_GetGenericError(): + */ +#ifdef _WIN32 +#define ASOCK_ENOTCONN WSAENOTCONN +#define ASOCK_ENOTSOCK WSAENOTSOCK +#define ASOCK_EADDRINUSE WSAEADDRINUSE +#define ASOCK_ECONNECTING WSAEWOULDBLOCK +#define ASOCK_EWOULDBLOCK WSAEWOULDBLOCK +#define ASOCK_ENETUNREACH WSAENETUNREACH +#define ASOCK_ECONNRESET WSAECONNRESET +#define ASOCK_ECONNABORTED WSAECONNABORTED +#define ASOCK_EPIPE ERROR_NO_DATA +#else +#define ASOCK_ENOTCONN ENOTCONN +#define ASOCK_ENOTSOCK ENOTSOCK +#define ASOCK_EADDRINUSE EADDRINUSE +#define ASOCK_ECONNECTING EINPROGRESS +#define ASOCK_EWOULDBLOCK EWOULDBLOCK +#define ASOCK_ENETUNREACH ENETUNREACH +#define ASOCK_ECONNRESET ECONNRESET +#define ASOCK_ECONNABORTED ECONNABORTED +#define ASOCK_EPIPE EPIPE +#endif /* * Websocket close status codes -- @@ -160,6 +180,15 @@ typedef enum AsyncSocketState { AsyncSocketClosed, } AsyncSocketState; + +typedef struct AsyncSocketNetworkStats { + uint32 cwndBytes; /* maximum outstanding bytes */ + uint32 rttSmoothedAvgMillis; /* rtt average in milliseconds */ + uint32 rttSmoothedVarMillis; /* rtt variance in milliseconds */ + uint32 queuedBytes; /* unsent bytes in send queue */ + uint32 inflightBytes; /* current outstanding bytes */ +} AsyncSocketNetworkStats; + AsyncSocketState AsyncSocket_GetState(AsyncSocket *sock); const char * AsyncSocket_Err2String(int err); @@ -217,7 +246,7 @@ typedef void (*AsyncSocketSslAcceptFn) (Bool status, AsyncSocket *asock, void *clientData); typedef void (*AsyncSocketSslConnectFn) (Bool status, AsyncSocket *asock, void *clientData); -typedef void (*AsyncSocketCloseCb) (AsyncSocket *asock); +typedef void (*AsyncSocketCloseFn) (AsyncSocket *asock, void *clientData); /* * Listen on port and fire callback with new asock @@ -239,7 +268,6 @@ AsyncSocket *AsyncSocket_ListenVMCI(unsigned int cid, void *clientData, AsyncSocketPollParams *pollParams, int *outError); -#ifndef VMX86_TOOLS AsyncSocket *AsyncSocket_ListenWebSocket(const char *addrStr, unsigned int port, Bool useSSL, @@ -269,16 +297,14 @@ AsyncSocket *AsyncSocket_ListenWebSocketUDS(const char *pipeName, void *clientData, AsyncSocketPollParams *pollParams, int *outError); - AsyncSocket *AsyncSocket_ListenSocketUDS(const char *pipeName, AsyncSocketConnectFn connectFn, void *clientData, AsyncSocketPollParams *pollParams, int *outError); - -#endif #endif + /* * Connect to address:port and fire callback with new asock */ @@ -322,7 +348,6 @@ AsyncSocket_CreateNamedPipe(const char *pipeName, int *error); #endif -#if !defined VMX86_TOOLS || TARGET_OS_IPHONE AsyncSocket * AsyncSocket_ConnectWebSocket(const char *url, struct _SSLVerifyParam *sslVerifyParam, @@ -346,7 +371,6 @@ AsyncSocket_ConnectProxySocket(const char *url, AsyncSocketConnectFlags flags, AsyncSocketPollParams *pollParams, int *error); -#endif /* * Initiate SSL connection on existing asock, with optional cert verification @@ -383,10 +407,8 @@ int AsyncSocket_UseNodelay(AsyncSocket *asock, Bool nodelay); /* * Set TCP timeout values on this AsyncSocket. */ -#ifdef VMX86_SERVER int AsyncSocket_SetTCPTimeouts(AsyncSocket *asock, int keepIdle, int keepIntvl, int keepCnt); -#endif /* * Waits until at least one packet is received or times out. @@ -449,6 +471,8 @@ int AsyncSocket_Send(AsyncSocket *asock, void *buf, int len, AsyncSocketSendFn sendFn, void *clientData); int AsyncSocket_IsSendBufferFull(AsyncSocket *asock); +int AsyncSocket_GetNetworkStats(AsyncSocket *asock, + AsyncSocketNetworkStats *stats); int AsyncSocket_CancelRecv(AsyncSocket *asock, int *partialRecvd, void **recvBuf, void **recvFn); int AsyncSocket_CancelRecvEx(AsyncSocket *asock, int *partialRecvd, void **recvBuf, @@ -477,14 +501,7 @@ Bool AsyncSocket_SetBufferSizes(AsyncSocket *asock, // IN */ void AsyncSocket_SetCloseOptions(AsyncSocket *asock, int flushEnabledMaxWaitMsec, - AsyncSocketCloseCb closeCb); - -/* - * Send websocket close frame. - */ -int -AsyncSocket_SendWebSocketCloseFrame(AsyncSocket *asock, - uint16 closeStatus); + AsyncSocketCloseFn closeCb); /* * Close the connection and destroy the asock. @@ -504,7 +521,7 @@ char *AsyncSocket_GetWebSocketCookie(AsyncSocket *asock); /* * Retrieve the close status, if received, for a websocket connection */ -uint16 AsyncSocket_GetWebSocketCloseStatus(const AsyncSocket *asock); +uint16 AsyncSocket_GetWebSocketCloseStatus(AsyncSocket *asock); /* * Set low-latency mode for sends: @@ -521,11 +538,6 @@ const char *AsyncSocket_GetWebSocketProtocol(AsyncSocket *asock); */ int AsyncSocket_GetWebSocketError(AsyncSocket *asock); -/* - * Get error code for proxySocket failure - */ -int AsyncSocket_GetProxySocketError(AsyncSocket *asock); - const char * stristr(const char *s, const char *find); /* diff --git a/open-vm-tools/lib/include/vm_product_versions.h b/open-vm-tools/lib/include/vm_product_versions.h index 214901438..d3d3b0cad 100644 --- a/open-vm-tools/lib/include/vm_product_versions.h +++ b/open-vm-tools/lib/include/vm_product_versions.h @@ -39,7 +39,7 @@ #if defined(VMX86_VIEWCLIENT) #define PRODUCT_VERSION 4,1,0,PRODUCT_BUILD_NUMBER_NUMERIC #elif defined(VMX86_VMRC) /* check VMX86_VMRC before VMX86_DESKTOP */ - #define PRODUCT_VERSION 8,1,0,PRODUCT_BUILD_NUMBER_NUMERIC /* VMRC_VERSION_NUMBER below has to match this */ + #define PRODUCT_VERSION 9,0,0,PRODUCT_BUILD_NUMBER_NUMERIC /* VMRC_VERSION_NUMBER below has to match this */ #elif defined(VMX86_FLEX) /* check VMX86_FLEX before VMX86_DESKTOP */ #define PRODUCT_VERSION 8,0,0,PRODUCT_BUILD_NUMBER_NUMERIC /* FLEX_VERSION_NUMBER below has to match this */ #elif defined(VMX86_TOOLS) @@ -164,8 +164,8 @@ #define WORKSTATION_VERSION "e.x.p" #define PLAYER_VERSION_NUMBER "12.0.0" /* this version number should always match real Player version number */ #define PLAYER_VERSION "e.x.p" -#define VMRC_VERSION_NUMBER "8.1.0" /* this version number should always match real VMRC version number */ -#define VMRC_VERSION "8.1.0" +#define VMRC_VERSION_NUMBER "9.0.0" /* this version number should always match real VMRC version number */ +#define VMRC_VERSION "9.0.0" #define FLEX_CLIENT_VERSION_NUMBER "8.0.0" #define FLEX_CLIENT_VERSION "e.x.p" @@ -358,7 +358,7 @@ */ #define PRODUCT_MAC_DESKTOP_VERSION_STRING_FOR_LICENSE "8.0" #define PRODUCT_PLAYER_VERSION_STRING_FOR_LICENSE "12.0" -#define PRODUCT_VMRC_VERSION_STRING_FOR_LICENSE "8.1" +#define PRODUCT_VMRC_VERSION_STRING_FOR_LICENSE "9.0" #define PRODUCT_FLEX_VERSION_STRING_FOR_LICENSE "8.0" #if defined(VMX86_TOOLS)