diff options
Diffstat (limited to 'src/VBox/NetworkServices/NAT/RTWinSocketPair.cpp')
-rw-r--r-- | src/VBox/NetworkServices/NAT/RTWinSocketPair.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/VBox/NetworkServices/NAT/RTWinSocketPair.cpp b/src/VBox/NetworkServices/NAT/RTWinSocketPair.cpp new file mode 100644 index 00000000..c05f9656 --- /dev/null +++ b/src/VBox/NetworkServices/NAT/RTWinSocketPair.cpp @@ -0,0 +1,225 @@ +/* $Id: RTWinSocketPair.cpp $ */ +/** @file + * NAT Network - socketpair(2) emulation for winsock. + */ + +/* + * Copyright (C) 2013-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/cdefs.h> +#include <iprt/errcore.h> + +#include <iprt/errcore.h> + +#include <iprt/win/winsock2.h> +#include <iprt/win/windows.h> + +#include <stdio.h> +#include <iprt/log.h> + +extern "C" int RTWinSocketPair(int domain, int type, int protocol, SOCKET socket_vector[2]) +{ + LogFlowFunc(("ENTER: domain:%d, type:%d, protocol:%d, socket_vector:%p\n", + domain, type, protocol, socket_vector)); + switch (domain) + { + case AF_INET: + break; + case AF_INET6: /* I dobt we really need it. */ + default: + AssertMsgFailedReturn(("Unsuported domain:%d\n", domain), + VERR_INVALID_PARAMETER); + } + + switch(type) + { + case SOCK_STREAM: + case SOCK_DGRAM: + break; + default: + AssertMsgFailedReturn(("Unsuported type:%d\n", type), + VERR_INVALID_PARAMETER); + } + + AssertPtrReturn(socket_vector, VERR_INVALID_PARAMETER); + if (!socket_vector) + return VERR_INVALID_PARAMETER; + + socket_vector[0] = socket_vector[1] = INVALID_SOCKET; + + SOCKET listener = INVALID_SOCKET; + + union { + struct sockaddr_in in_addr; + struct sockaddr addr; + } sa[2]; + + int cb = sizeof(sa); + memset(&sa, 0, cb); + + sa[0].in_addr.sin_family = domain; + sa[0].in_addr.sin_addr.s_addr = RT_H2N_U32(INADDR_LOOPBACK); + sa[0].in_addr.sin_port = 0; + cb = sizeof(sa[0]); + + if (type == SOCK_STREAM) + { + listener = WSASocket(domain, type, protocol, 0, NULL, 0); + + if (listener == INVALID_SOCKET) + { + return VERR_INTERNAL_ERROR; + } + + int reuse = 1; + cb = sizeof(int); + int rc = setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, cb); + + if (rc) + { + goto close_socket; + } + + cb = sizeof(sa[0]); + rc = bind(listener, &sa[0].addr, cb); + if(rc) + { + goto close_socket; + } + + memset(&sa[0], 0, cb); + rc = getsockname(listener, &sa[0].addr, &cb); + if (rc) + { + goto close_socket; + } + + rc = listen(listener, 1); + if (rc) + { + goto close_socket; + } + + socket_vector[0] = WSASocket(domain, type, protocol, 0, NULL, 0); + if (socket_vector[0] == INVALID_SOCKET) + { + goto close_socket; + } + + rc = connect(socket_vector[0], &sa[0].addr, cb); + if (rc) + goto close_socket; + + + socket_vector[1] = accept(listener, NULL, NULL); + if (socket_vector[1] == INVALID_SOCKET) + { + goto close_socket; + } + + closesocket(listener); + } + else + { + socket_vector[0] = WSASocket(domain, type, protocol, 0, NULL, 0); + + cb = sizeof(sa[0]); + int rc = bind(socket_vector[0], &sa[0].addr, cb); + Assert(rc != SOCKET_ERROR); + if (rc == SOCKET_ERROR) + { + goto close_socket; + } + + sa[1].in_addr.sin_family = domain; + sa[1].in_addr.sin_addr.s_addr = RT_H2N_U32(INADDR_LOOPBACK); + sa[1].in_addr.sin_port = 0; + + socket_vector[1] = WSASocket(domain, type, protocol, 0, NULL, 0); + rc = bind(socket_vector[1], &sa[1].addr, cb); + Assert(rc != SOCKET_ERROR); + if (rc == SOCKET_ERROR) + { + goto close_socket; + } + + { + u_long mode = 0; + rc = ioctlsocket(socket_vector[0], FIONBIO, &mode); + AssertMsgReturn(rc != SOCKET_ERROR, + ("ioctl error: %d\n", WSAGetLastError()), + VERR_INTERNAL_ERROR); + + rc = ioctlsocket(socket_vector[1], FIONBIO, &mode); + AssertMsgReturn(rc != SOCKET_ERROR, + ("ioctl error: %d\n", WSAGetLastError()), + VERR_INTERNAL_ERROR); + } + + memset(&sa, 0, 2 * cb); + rc = getsockname(socket_vector[0], &sa[0].addr, &cb); + Assert(rc != SOCKET_ERROR); + if (rc == SOCKET_ERROR) + { + goto close_socket; + } + + rc = getsockname(socket_vector[1], &sa[1].addr, &cb); + Assert(rc != SOCKET_ERROR); + if (rc == SOCKET_ERROR) + { + goto close_socket; + } + + rc = connect(socket_vector[0], &sa[1].addr, cb); + Assert(rc != SOCKET_ERROR); + if (rc == SOCKET_ERROR) + { + goto close_socket; + } + + rc = connect(socket_vector[1], &sa[0].addr, cb); + Assert(rc != SOCKET_ERROR); + if (rc == SOCKET_ERROR) + { + goto close_socket; + } + } + + for (int i = 0; i < 2; ++i) { + SOCKET s = socket_vector[i]; + u_long mode = 1; + + int status = ioctlsocket(s, FIONBIO, &mode); + if (status == SOCKET_ERROR) { + LogRel(("FIONBIO: %R[sockerr]\n", WSAGetLastError())); + } + } + + LogFlowFuncLeaveRC(VINF_SUCCESS); + return VINF_SUCCESS; + +close_socket: + if (listener != INVALID_SOCKET) + closesocket(listener); + + if (socket_vector[0] != INVALID_SOCKET) + closesocket(socket_vector[0]); + + if (socket_vector[1] != INVALID_SOCKET) + closesocket(socket_vector[1]); + + LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR); + return VERR_INTERNAL_ERROR; +} |