1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include <grpc/support/port_platform.h>
15 #ifdef GPR_WINDOWS
16
17 #include <winsock2.h>
18 #include <ws2tcpip.h>
19
20 #include "absl/log/check.h"
21 #include "absl/log/log.h"
22 #include "absl/status/status.h"
23 #include "src/core/lib/event_engine/windows/win_socket.h"
24 #include "src/core/lib/iomgr/error.h"
25 #include "test/core/event_engine/windows/create_sockpair.h"
26
27 namespace grpc_event_engine {
28 namespace experimental {
29
GetSomeIpv4LoopbackAddress()30 sockaddr_in GetSomeIpv4LoopbackAddress() {
31 sockaddr_in addr;
32 memset(&addr, 0, sizeof(addr));
33 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
34 addr.sin_family = AF_INET;
35 return addr;
36 }
37
CreateSockpair(SOCKET sockpair[2],DWORD flags)38 void CreateSockpair(SOCKET sockpair[2], DWORD flags) {
39 SOCKET svr_sock = INVALID_SOCKET;
40 SOCKET lst_sock = INVALID_SOCKET;
41 SOCKET cli_sock = INVALID_SOCKET;
42 auto addr = GetSomeIpv4LoopbackAddress();
43 int addr_len = sizeof(addr);
44
45 lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, flags);
46 CHECK(lst_sock != INVALID_SOCKET);
47
48 CHECK(bind(lst_sock, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR);
49 CHECK(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
50 CHECK(getsockname(lst_sock, (sockaddr*)&addr, &addr_len) != SOCKET_ERROR);
51
52 cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, flags);
53 CHECK(cli_sock != INVALID_SOCKET);
54
55 auto result =
56 WSAConnect(cli_sock, (sockaddr*)&addr, addr_len, NULL, NULL, NULL, NULL);
57 if (result != 0) {
58 VLOG(2)
59 << GRPC_WSA_ERROR(WSAGetLastError(), "Failed in WSAConnect").ToString();
60 abort();
61 }
62 svr_sock = accept(lst_sock, (sockaddr*)&addr, &addr_len);
63 CHECK(svr_sock != INVALID_SOCKET);
64 closesocket(lst_sock);
65 // TODO(hork): see if we can migrate this to IPv6, or break up the socket prep
66 // stages.
67 // Historical note: This method creates an ipv4 sockpair, which cannot
68 // be made dual stack. This was silently preventing TCP_NODELAY from being
69 // enabled, but not causing an unrecoverable error. So this is left as a
70 // logged status. WSAEINVAL is expected.
71 auto status = PrepareSocket(cli_sock);
72 // if (!status.ok()) {
73 // VLOG(2) << "Error preparing client socket: " << status.ToString();
74 // }
75 status = PrepareSocket(svr_sock);
76 // if (!status.ok()) {
77 // VLOG(2) << "Error preparing server socket: " << status.ToString();
78 // }
79
80 sockpair[0] = svr_sock;
81 sockpair[1] = cli_sock;
82 }
83
84 } // namespace experimental
85 } // namespace grpc_event_engine
86
87 #endif // GPR_WINDOWS
88