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/status/status.h"
21
22 #include "src/core/lib/event_engine/windows/win_socket.h"
23 #include "src/core/lib/iomgr/error.h"
24 #include "test/core/event_engine/windows/create_sockpair.h"
25
26 namespace grpc_event_engine {
27 namespace experimental {
28
GetSomeIpv4LoopbackAddress()29 sockaddr_in GetSomeIpv4LoopbackAddress() {
30 sockaddr_in addr;
31 memset(&addr, 0, sizeof(addr));
32 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
33 addr.sin_family = AF_INET;
34 return addr;
35 }
36
CreateSockpair(SOCKET sockpair[2],DWORD flags)37 void CreateSockpair(SOCKET sockpair[2], DWORD flags) {
38 SOCKET svr_sock = INVALID_SOCKET;
39 SOCKET lst_sock = INVALID_SOCKET;
40 SOCKET cli_sock = INVALID_SOCKET;
41 auto addr = GetSomeIpv4LoopbackAddress();
42 int addr_len = sizeof(addr);
43
44 lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, flags);
45 GPR_ASSERT(lst_sock != INVALID_SOCKET);
46
47 GPR_ASSERT(bind(lst_sock, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR);
48 GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
49 GPR_ASSERT(getsockname(lst_sock, (sockaddr*)&addr, &addr_len) !=
50 SOCKET_ERROR);
51
52 cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, flags);
53 GPR_ASSERT(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 gpr_log(GPR_DEBUG, "%s",
59 GRPC_WSA_ERROR(WSAGetLastError(), "Failed in WSAConnect")
60 .ToString()
61 .c_str());
62 abort();
63 }
64 svr_sock = accept(lst_sock, (sockaddr*)&addr, &addr_len);
65 GPR_ASSERT(svr_sock != INVALID_SOCKET);
66 closesocket(lst_sock);
67 // TODO(hork): see if we can migrate this to IPv6, or break up the socket prep
68 // stages.
69 // Historical note: This method creates an ipv4 sockpair, which cannot
70 // be made dual stack. This was silently preventing TCP_NODELAY from being
71 // enabled, but not causing an unrecoverable error. So this is left as a
72 // logged status. WSAEINVAL is expected.
73 auto status = PrepareSocket(cli_sock);
74 // if (!status.ok()) {
75 // gpr_log(GPR_DEBUG, "Error preparing client socket: %s",
76 // status.ToString().c_str());
77 // }
78 status = PrepareSocket(svr_sock);
79 // if (!status.ok()) {
80 // gpr_log(GPR_DEBUG, "Error preparing server socket: %s",
81 // status.ToString().c_str());
82 // }
83
84 sockpair[0] = svr_sock;
85 sockpair[1] = cli_sock;
86 }
87
88 } // namespace experimental
89 } // namespace grpc_event_engine
90
91 #endif // GPR_WINDOWS
92