/* $Id: RTWinSocketPair.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */ /** @file * NAT Network - socketpair(2) emulation for winsock. */ /* * Copyright (C) 2013-2023 Oracle and/or its affiliates. * * This file is part of VirtualBox base platform packages, as * available from https://www.virtualbox.org. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, in version 3 of the * License. * * 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 GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * SPDX-License-Identifier: GPL-3.0-only */ #include #include #include #include #include #include #include #include #include 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; }