diff options
Diffstat (limited to 'src/VBox/Runtime/r3/socket.cpp')
-rw-r--r-- | src/VBox/Runtime/r3/socket.cpp | 119 |
1 files changed, 90 insertions, 29 deletions
diff --git a/src/VBox/Runtime/r3/socket.cpp b/src/VBox/Runtime/r3/socket.cpp index 42d42883..8678c37b 100644 --- a/src/VBox/Runtime/r3/socket.cpp +++ b/src/VBox/Runtime/r3/socket.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -33,6 +33,7 @@ # include <ws2tcpip.h> #else /* !RT_OS_WINDOWS */ # include <errno.h> +# include <sys/select.h> # include <sys/stat.h> # include <sys/socket.h> # include <netinet/in.h> @@ -110,6 +111,15 @@ /** How many pending connection. */ #define RTTCP_SERVER_BACKLOG 10 +/* Limit read and write sizes on Windows and OS/2. */ +#ifdef RT_OS_WINDOWS +# define RTSOCKET_MAX_WRITE (INT_MAX / 2) +# define RTSOCKET_MAX_READ (INT_MAX / 2) +#elif defined(RT_OS_OS2) +# define RTSOCKET_MAX_WRITE 0x10000 +# define RTSOCKET_MAX_READ 0x10000 +#endif + /******************************************************************************* * Structures and Typedefs * @@ -135,13 +145,15 @@ typedef struct RTSOCKETINT /** Indicates whether the socket is operating in blocking or non-blocking mode * currently. */ bool fBlocking; +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + /** The pollset currently polling this socket. This is NIL if no one is + * polling. */ + RTPOLLSET hPollSet; +#endif #ifdef RT_OS_WINDOWS /** The event semaphore we've associated with the socket handle. * This is WSA_INVALID_EVENT if not done. */ WSAEVENT hEvent; - /** The pollset currently polling this socket. This is NIL if no one is - * polling. */ - RTPOLLSET hPollSet; /** The events we're polling for. */ uint32_t fPollEvts; /** The events we're currently subscribing to with WSAEventSelect. @@ -397,9 +409,11 @@ int rtSocketCreateForNative(RTSOCKETINT **ppSocket, RTSOCKETNATIVE hNative) pThis->hNative = hNative; pThis->fClosed = false; pThis->fBlocking = true; +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + pThis->hPollSet = NIL_RTPOLLSET; +#endif #ifdef RT_OS_WINDOWS pThis->hEvent = WSA_INVALID_EVENT; - pThis->hPollSet = NIL_RTPOLLSET; pThis->fPollEvts = 0; pThis->fSubscribedEvts = 0; #endif @@ -853,8 +867,8 @@ RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size for (;;) { rtSocketErrorReset(); -#ifdef RT_OS_WINDOWS - int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead; +#ifdef RTSOCKET_MAX_READ + int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead; #else size_t cbNow = cbToRead; #endif @@ -920,8 +934,8 @@ RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t cbToRead = cbBuffer; rtSocketErrorReset(); RTSOCKADDRUNION u; -#ifdef RT_OS_WINDOWS - int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead; +#ifdef RTSOCKET_MAX_READ + int cbNow = cbToRead >= RTSOCKET_MAX_READ ? RTSOCKET_MAX_READ : (int)cbToRead; int cbAddr = sizeof(u); #else size_t cbNow = cbToRead; @@ -967,8 +981,8 @@ RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffe /* * Try write all at once. */ -#ifdef RT_OS_WINDOWS - int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer; +#ifdef RTSOCKET_MAX_WRITE + int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; #else size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer; #endif @@ -994,8 +1008,8 @@ RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffe pvBuffer = (char const *)pvBuffer + cbWritten; /* send */ -#ifdef RT_OS_WINDOWS - cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer; +#ifdef RTSOCKET_MAX_WRITE + cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; #else cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer; #endif @@ -1056,7 +1070,7 @@ RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuf * Must write all at once, otherwise it is a failure. */ #ifdef RT_OS_WINDOWS - int cbNow = cbBuffer >= INT_MAX / 2 ? INT_MAX / 2 : (int)cbBuffer; + int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; #else size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer; #endif @@ -1201,9 +1215,13 @@ RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, si return rc; rtSocketErrorReset(); -#ifdef RT_OS_WINDOWS - int cbNow = cbBuffer >= INT_MAX/2 ? INT_MAX/2 : (int)cbBuffer; +#ifdef RTSOCKET_MAX_READ + int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; +#else + size_t cbNow = cbBuffer; +#endif +#ifdef RT_OS_WINDOWS int cbRead = recv(pThis->hNative, (char *)pvBuffer, cbNow, MSG_NOSIGNAL); if (cbRead >= 0) { @@ -1216,7 +1234,7 @@ RTDECL(int) RTSocketReadNB(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, si if (rc == VERR_TRY_AGAIN) rc = VINF_TRY_AGAIN; #else - ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbBuffer, MSG_NOSIGNAL); + ssize_t cbRead = recv(pThis->hNative, pvBuffer, cbNow, MSG_NOSIGNAL); if (cbRead >= 0) *pcbRead = cbRead; else if (errno == EAGAIN) @@ -1249,11 +1267,14 @@ RTDECL(int) RTSocketWriteNB(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuf return rc; rtSocketErrorReset(); -#ifdef RT_OS_WINDOWS - int cbNow = RT_MIN((int)cbBuffer, INT_MAX/2); +#ifdef RTSOCKET_MAX_WRITE + int cbNow = cbBuffer >= RTSOCKET_MAX_WRITE ? RTSOCKET_MAX_WRITE : (int)cbBuffer; +#else + size_t cbNow = cbBuffer; +#endif +#ifdef RT_OS_WINDOWS int cbWritten = send(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL); - if (cbWritten >= 0) { *pcbWritten = cbWritten; @@ -1752,7 +1773,6 @@ int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValu return rc; } -#ifdef RT_OS_WINDOWS /** * Internal RTPollSetAdd helper that returns the handle that should be added to @@ -1761,29 +1781,37 @@ int rtSocketSetOpt(RTSOCKET hSocket, int iLevel, int iOption, void const *pvValu * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure. * @param hSocket The socket handle. * @param fEvents The events we're polling for. - * @param ph where to put the primary handle. + * @param phNative Where to put the primary handle. */ -int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PHANDLE ph) +int rtSocketPollGetHandle(RTSOCKET hSocket, uint32_t fEvents, PRTHCINTPTR phNative) { RTSOCKETINT *pThis = hSocket; AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE); +#ifdef RT_OS_WINDOWS AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS); int rc = VINF_SUCCESS; if (pThis->hEvent != WSA_INVALID_EVENT) - *ph = pThis->hEvent; + *phNative = (RTHCINTPTR)pThis->hEvent; else { - *ph = pThis->hEvent = WSACreateEvent(); + pThis->hEvent = WSACreateEvent(); + *phNative = (RTHCINTPTR)pThis->hEvent; if (pThis->hEvent == WSA_INVALID_EVENT) rc = rtSocketError(); } rtSocketUnlock(pThis); return rc; + +#else /* !RT_OS_WINDOWS */ + *phNative = (RTHCUINTPTR)pThis->hNative; + return VINF_SUCCESS; +#endif /* !RT_OS_WINDOWS */ } +#ifdef RT_OS_WINDOWS /** * Undos the harm done by WSAEventSelect. @@ -1853,6 +1881,10 @@ static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents) return rc; } +#endif /* RT_OS_WINDOWS */ + + +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) /** * Checks for pending events. @@ -1863,12 +1895,13 @@ static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents) */ static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents) { - int rc = VINF_SUCCESS; - uint32_t fRetEvents = 0; + uint32_t fRetEvents = 0; LogFlowFunc(("pThis=%#p fEvents=%#x\n", pThis, fEvents)); +# ifdef RT_OS_WINDOWS /* Make sure WSAEnumNetworkEvents returns what we want. */ + int rc = VINF_SUCCESS; if ((pThis->fSubscribedEvts & fEvents) != fEvents) rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents); @@ -1904,8 +1937,23 @@ static uint32_t rtSocketPollCheck(RTSOCKETINT *pThis, uint32_t fEvents) /* Fall back on select if we hit an error above. */ if (RT_FAILURE(rc)) { - /** @todo */ + + } + +#else /* RT_OS_OS2 */ + int aFds[4] = { pThis->hNative, pThis->hNative, pThis->hNative, -1 }; + int rc = os2_select(aFds, 1, 1, 1, 0); + if (rc > 0) + { + if (aFds[0] == pThis->hNative) + fRetEvents |= RTPOLL_EVT_READ; + if (aFds[1] == pThis->hNative) + fRetEvents |= RTPOLL_EVT_WRITE; + if (aFds[2] == pThis->hNative) + fRetEvents |= RTPOLL_EVT_ERROR; + fRetEvents &= fEvents; } +#endif /* RT_OS_OS2 */ LogFlowFunc(("fRetEvents=%#x\n", fRetEvents)); return fRetEvents; @@ -1939,6 +1987,8 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent RTSOCKETINT *pThis = hSocket; AssertPtrReturn(pThis, UINT32_MAX); AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, UINT32_MAX); + /** @todo This isn't quite sane. Replace by critsect and open up concurrent + * reads and writes! */ if (rtSocketTryLock(pThis)) pThis->hPollSet = hPollSet; else @@ -1948,6 +1998,7 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent } /* (rtSocketPollCheck will reset the event object). */ +# ifdef RT_OS_WINDOWS uint32_t fRetEvents = pThis->fEventsSaved; pThis->fEventsSaved = 0; /* Reset */ fRetEvents |= rtSocketPollCheck(pThis, fEvents); @@ -1967,12 +2018,17 @@ uint32_t rtSocketPollStart(RTSOCKET hSocket, RTPOLLSET hPollSet, uint32_t fEvent } } } +# else + uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents); +# endif if (fRetEvents || fNoWait) { if (pThis->cUsers == 1) { +# ifdef RT_OS_WINDOWS rtSocketPollClearEventAndRestoreBlocking(pThis); +# endif pThis->hPollSet = NIL_RTPOLLSET; } ASMAtomicDecU32(&pThis->cUsers); @@ -2008,6 +2064,7 @@ uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, /* Harvest events and clear the event mask for the next round of polling. */ uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents); +# ifdef RT_OS_WINDOWS pThis->fPollEvts = 0; /* @@ -2021,15 +2078,19 @@ uint32_t rtSocketPollDone(RTSOCKET hSocket, uint32_t fEvents, bool fFinalEntry, pThis->fEventsSaved = fRetEvents; fRetEvents = 0; } +# endif /* Make the socket blocking again and unlock the handle. */ if (pThis->cUsers == 1) { +# ifdef RT_OS_WINDOWS rtSocketPollClearEventAndRestoreBlocking(pThis); +# endif pThis->hPollSet = NIL_RTPOLLSET; } ASMAtomicDecU32(&pThis->cUsers); return fRetEvents; } -#endif /* RT_OS_WINDOWS */ +#endif /* RT_OS_WINDOWS || RT_OS_OS2 */ + |