summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/r3/socket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/r3/socket.cpp')
-rw-r--r--src/VBox/Runtime/r3/socket.cpp292
1 files changed, 247 insertions, 45 deletions
diff --git a/src/VBox/Runtime/r3/socket.cpp b/src/VBox/Runtime/r3/socket.cpp
index b989e28cf..e09ead6df 100644
--- a/src/VBox/Runtime/r3/socket.cpp
+++ b/src/VBox/Runtime/r3/socket.cpp
@@ -1,10 +1,10 @@
-/* $Id: socket.cpp $ */
+/* $Id: socket.cpp 37196 2011-05-24 14:50:05Z vboxsync $ */
/** @file
* IPRT - Network Sockets.
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -220,6 +220,83 @@ int rtSocketResolverError(void)
/**
+ * Converts from a native socket address to a generic IPRT network address.
+ *
+ * @returns IPRT status code.
+ * @param pSrc The source address.
+ * @param cbSrc The size of the source address.
+ * @param pAddr Where to return the generic IPRT network
+ * address.
+ */
+static int rtSocketNetAddrFromAddr(RTSOCKADDRUNION const *pSrc, size_t cbSrc, PRTNETADDR pAddr)
+{
+ /*
+ * Convert the address.
+ */
+ if ( cbSrc == sizeof(struct sockaddr_in)
+ && pSrc->Addr.sa_family == AF_INET)
+ {
+ RT_ZERO(*pAddr);
+ pAddr->enmType = RTNETADDRTYPE_IPV4;
+ pAddr->uPort = RT_N2H_U16(pSrc->Ipv4.sin_port);
+ pAddr->uAddr.IPv4.u = pSrc->Ipv4.sin_addr.s_addr;
+ }
+#ifdef IPRT_WITH_TCPIP_V6
+ else if ( cbSrc == sizeof(struct sockaddr_in6)
+ && pSrc->Addr.sa_family == AF_INET6)
+ {
+ RT_ZERO(*pAddr);
+ pAddr->enmType = RTNETADDRTYPE_IPV6;
+ pAddr->uPort = RT_N2H_U16(pSrc->Ipv6.sin6_port);
+ pAddr->uAddr.IPv6.au32[0] = pSrc->Ipv6.sin6_addr.s6_addr32[0];
+ pAddr->uAddr.IPv6.au32[1] = pSrc->Ipv6.sin6_addr.s6_addr32[1];
+ pAddr->uAddr.IPv6.au32[2] = pSrc->Ipv6.sin6_addr.s6_addr32[2];
+ pAddr->uAddr.IPv6.au32[3] = pSrc->Ipv6.sin6_addr.s6_addr32[3];
+ }
+#endif
+ else
+ return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Converts from a generic IPRT network address to a native socket address.
+ *
+ * @returns IPRT status code.
+ * @param pAddr Pointer to the generic IPRT network address.
+ * @param pDst The source address.
+ * @param cbSrc The size of the source address.
+ */
+static int rtSocketAddrFromNetAddr(PCRTNETADDR pAddr, RTSOCKADDRUNION *pDst, size_t cbDst)
+{
+ RT_BZERO(pDst, cbDst);
+ if ( pAddr->enmType == RTNETADDRTYPE_IPV4
+ && cbDst >= sizeof(struct sockaddr_in))
+ {
+ pDst->Addr.sa_family = AF_INET;
+ pDst->Ipv4.sin_port = RT_H2N_U16(pAddr->uPort);
+ pDst->Ipv4.sin_addr.s_addr = pAddr->uAddr.IPv4.u;
+ }
+#ifdef IPRT_WITH_TCPIP_V6
+ else if ( pAddr->enmType == RTNETADDRTYPE_IPV6
+ && cbDst >= sizeof(struct sockaddr_in6))
+ {
+ pDst->Addr.sa_family = AF_INET6;
+ pDst->Ipv6.sin6_port = RT_H2N_U16(pAddr->uPort);
+ pSrc->Ipv6.sin6_addr.s6_addr32[0] = pAddr->uAddr.IPv6.au32[0];
+ pSrc->Ipv6.sin6_addr.s6_addr32[1] = pAddr->uAddr.IPv6.au32[1];
+ pSrc->Ipv6.sin6_addr.s6_addr32[2] = pAddr->uAddr.IPv6.au32[2];
+ pSrc->Ipv6.sin6_addr.s6_addr32[3] = pAddr->uAddr.IPv6.au32[3];
+ }
+#endif
+ else
+ return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
+ return VINF_SUCCESS;
+}
+
+
+/**
* Tries to lock the socket for exclusive usage by the calling thread.
*
* Call rtSocketUnlock() to unlock.
@@ -504,6 +581,64 @@ RTDECL(int) RTSocketSetInheritance(RTSOCKET hSocket, bool fInheritable)
}
+RTDECL(int) RTSocketParseInetAddress(const char *pszAddress, unsigned uPort, PRTNETADDR pAddr)
+{
+ int rc;
+
+ /*
+ * Validate input.
+ */
+ AssertReturn(uPort > 0, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
+
+#ifdef RT_OS_WINDOWS
+ /*
+ * Initialize WinSock and check version.
+ */
+ WORD wVersionRequested = MAKEWORD(1, 1);
+ WSADATA wsaData;
+ rc = WSAStartup(wVersionRequested, &wsaData);
+ if (wsaData.wVersion != wVersionRequested)
+ {
+ AssertMsgFailed(("Wrong winsock version\n"));
+ return VERR_NOT_SUPPORTED;
+ }
+#endif
+
+ /*
+ * Resolve the address.
+ */
+ /** @todo this only supports IPv4, and IPv6 support needs to be added.
+ * It probably needs to be converted to getnameinfo(). */
+ struct hostent *pHostEnt = NULL;
+ pHostEnt = gethostbyname(pszAddress);
+ if (!pHostEnt)
+ {
+ struct in_addr InAddr;
+ InAddr.s_addr = inet_addr(pszAddress);
+ pHostEnt = gethostbyaddr((char *)&InAddr, 4, AF_INET);
+ if (!pHostEnt)
+ {
+ rc = rtSocketResolverError();
+ AssertMsgFailed(("Could not resolve '%s', rc=%Rrc\n", pszAddress, rc));
+ return rc;
+ }
+ }
+
+ if (pHostEnt->h_addrtype == AF_INET)
+ {
+ RT_ZERO(*pAddr);
+ pAddr->enmType = RTNETADDRTYPE_IPV4;
+ pAddr->uPort = uPort;
+ pAddr->uAddr.IPv4.u = ((struct in_addr *)pHostEnt->h_addr)->s_addr;
+ }
+ else
+ return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
+
+ return VINF_SUCCESS;
+}
+
+
RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
{
/*
@@ -573,6 +708,60 @@ RTDECL(int) RTSocketRead(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size
}
+RTDECL(int) RTSocketReadFrom(RTSOCKET hSocket, void *pvBuffer, size_t cbBuffer, size_t *pcbRead, PRTNETADDR pSrcAddr)
+{
+ /*
+ * Validate input.
+ */
+ RTSOCKETINT *pThis = hSocket;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
+ AssertReturn(cbBuffer > 0, VERR_INVALID_PARAMETER);
+ AssertPtr(pvBuffer);
+ AssertPtr(pcbRead);
+ AssertReturn(rtSocketTryLock(pThis), VERR_CONCURRENT_ACCESS);
+
+ int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Read data.
+ */
+ size_t cbRead = 0;
+ size_t cbToRead = cbBuffer;
+ rtSocketErrorReset();
+ RTSOCKADDRUNION u;
+#ifdef RT_OS_WINDOWS
+ int cbNow = cbToRead >= INT_MAX/2 ? INT_MAX/2 : (int)cbToRead;
+ int cbAddr = sizeof(u);
+#else
+ size_t cbNow = cbToRead;
+ socklen_t cbAddr = sizeof(u);
+#endif
+ ssize_t cbBytesRead = recvfrom(pThis->hNative, (char *)pvBuffer + cbRead, cbNow, MSG_NOSIGNAL, &u.Addr, &cbAddr);
+ if (cbBytesRead <= 0)
+ {
+ rc = rtSocketError();
+ Assert(RT_FAILURE_NP(rc) || cbBytesRead == 0);
+ if (RT_SUCCESS_NP(rc))
+ {
+ *pcbRead = 0;
+ rc = VINF_SUCCESS;
+ }
+ }
+ else
+ {
+ if (pSrcAddr)
+ rc = rtSocketNetAddrFromAddr(&u, cbAddr, pSrcAddr);
+ *pcbRead = cbBytesRead;
+ }
+
+ rtSocketUnlock(pThis);
+ return rc;
+}
+
+
RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer)
{
/*
@@ -642,6 +831,60 @@ RTDECL(int) RTSocketWrite(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffe
}
+RTDECL(int) RTSocketWriteTo(RTSOCKET hSocket, const void *pvBuffer, size_t cbBuffer, PCRTNETADDR pAddr)
+{
+ /*
+ * Validate input.
+ */
+ RTSOCKETINT *pThis = hSocket;
+ AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+ AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
+
+ /* no locking since UDP reads may be done concurrently to writes, and
+ * this is the normal use case of this code. */
+
+ int rc = rtSocketSwitchBlockingMode(pThis, true /* fBlocking */);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Figure out destination address. */
+ struct sockaddr *pSA = NULL;
+#ifdef RT_OS_WINDOWS
+ int cbSA = 0;
+#else
+ socklen_t cbSA = 0;
+#endif
+ RTSOCKADDRUNION u;
+ if (pAddr)
+ {
+ rc = rtSocketAddrFromNetAddr(pAddr, &u, sizeof(u));
+ if (RT_FAILURE(rc))
+ return rc;
+ pSA = &u.Addr;
+ cbSA = sizeof(u);
+ }
+
+ /*
+ * 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;
+#else
+ size_t cbNow = cbBuffer >= SSIZE_MAX ? SSIZE_MAX : cbBuffer;
+#endif
+ ssize_t cbWritten = sendto(pThis->hNative, (const char *)pvBuffer, cbNow, MSG_NOSIGNAL, pSA, cbSA);
+ if (RT_LIKELY((size_t)cbWritten == cbBuffer && cbWritten >= 0))
+ rc = VINF_SUCCESS;
+ else if (cbWritten < 0)
+ rc = rtSocketError();
+ else
+ rc = VERR_TOO_MUCH_DATA;
+
+ rtSocketUnlock(pThis);
+ return rc;
+}
+
+
RTDECL(int) RTSocketSgWrite(RTSOCKET hSocket, PCRTSGBUF pSgBuf)
{
/*
@@ -1084,47 +1327,6 @@ RTDECL(int) RTSocketShutdown(RTSOCKET hSocket, bool fRead, bool fWrite)
}
-/**
- * Converts from a native socket address to a generic IPRT network address.
- *
- * @returns IPRT status code.
- * @param pSrc The source address.
- * @param cbSrc The size of the source address.
- * @param pAddr Where to return the generic IPRT network
- * address.
- */
-static int rtSocketConvertAddress(RTSOCKADDRUNION const *pSrc, size_t cbSrc, PRTNETADDR pAddr)
-{
- /*
- * Convert the address.
- */
- if ( cbSrc == sizeof(struct sockaddr_in)
- && pSrc->Addr.sa_family == AF_INET)
- {
- RT_ZERO(*pAddr);
- pAddr->enmType = RTNETADDRTYPE_IPV4;
- pAddr->uPort = RT_N2H_U16(pSrc->Ipv4.sin_port);
- pAddr->uAddr.IPv4.u = pSrc->Ipv4.sin_addr.s_addr;
- }
-#ifdef IPRT_WITH_TCPIP_V6
- else if ( cbSrc == sizeof(struct sockaddr_in6)
- && pSrc->Addr.sa_family == AF_INET6)
- {
- RT_ZERO(*pAddr);
- pAddr->enmType = RTNETADDRTYPE_IPV6;
- pAddr->uPort = RT_N2H_U16(pSrc->Ipv6.sin6_port);
- pAddr->uAddr.IPv6.au32[0] = pSrc->Ipv6.sin6_addr.s6_addr32[0];
- pAddr->uAddr.IPv6.au32[1] = pSrc->Ipv6.sin6_addr.s6_addr32[1];
- pAddr->uAddr.IPv6.au32[2] = pSrc->Ipv6.sin6_addr.s6_addr32[2];
- pAddr->uAddr.IPv6.au32[3] = pSrc->Ipv6.sin6_addr.s6_addr32[3];
- }
-#endif
- else
- return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
- return VINF_SUCCESS;
-}
-
-
RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
{
/*
@@ -1147,7 +1349,7 @@ RTDECL(int) RTSocketGetLocalAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
#endif
RT_ZERO(u);
if (getsockname(pThis->hNative, &u.Addr, &cbAddr) == 0)
- rc = rtSocketConvertAddress(&u, cbAddr, pAddr);
+ rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
else
rc = rtSocketError();
@@ -1177,7 +1379,7 @@ RTDECL(int) RTSocketGetPeerAddress(RTSOCKET hSocket, PRTNETADDR pAddr)
#endif
RT_ZERO(u);
if (getpeername(pThis->hNative, &u.Addr, &cbAddr) == 0)
- rc = rtSocketConvertAddress(&u, cbAddr, pAddr);
+ rc = rtSocketNetAddrFromAddr(&u, cbAddr, pAddr);
else
rc = rtSocketError();