180814287SRaphael Isemann //===-- RNBSocketTest.cpp -------------------------------------------------===//
2efd065e6SChris Bieneman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6efd065e6SChris Bieneman //
7efd065e6SChris Bieneman //===----------------------------------------------------------------------===//
8efd065e6SChris Bieneman 
9efd065e6SChris Bieneman #include "gtest/gtest.h"
10efd065e6SChris Bieneman 
11efd065e6SChris Bieneman #include <arpa/inet.h>
12efd065e6SChris Bieneman #include <sys/sysctl.h>
13efd065e6SChris Bieneman #include <unistd.h>
14efd065e6SChris Bieneman 
15efd065e6SChris Bieneman #include "RNBDefs.h"
16efd065e6SChris Bieneman #include "RNBSocket.h"
17efd065e6SChris Bieneman #include "lldb/Host/Socket.h"
18efd065e6SChris Bieneman #include "lldb/Host/common/TCPSocket.h"
19c2fec2fbSRaphael Isemann #include "llvm/Testing/Support/Error.h"
20efd065e6SChris Bieneman 
21efd065e6SChris Bieneman using namespace lldb_private;
22efd065e6SChris Bieneman 
23efd065e6SChris Bieneman std::string hello = "Hello, world!";
24efd065e6SChris Bieneman std::string goodbye = "Goodbye!";
25efd065e6SChris Bieneman 
ServerCallbackv4(const void * baton,in_port_t port)26efd065e6SChris Bieneman static void ServerCallbackv4(const void *baton, in_port_t port) {
27efd065e6SChris Bieneman   auto child_pid = fork();
28efd065e6SChris Bieneman   if (child_pid == 0) {
29efd065e6SChris Bieneman     char addr_buffer[256];
30c59ccc02SJonas Devlieghere     sprintf(addr_buffer, "%s:%d", (const char *)baton, port);
31c2fec2fbSRaphael Isemann     llvm::Expected<std::unique_ptr<Socket>> socket_or_err =
32c2fec2fbSRaphael Isemann         Socket::TcpConnect(addr_buffer, false);
33c2fec2fbSRaphael Isemann     ASSERT_THAT_EXPECTED(socket_or_err, llvm::Succeeded());
34c2fec2fbSRaphael Isemann     Socket *client_socket = socket_or_err->get();
35c2fec2fbSRaphael Isemann 
36efd065e6SChris Bieneman     char buffer[32];
37efd065e6SChris Bieneman     size_t read_size = 32;
38c2fec2fbSRaphael Isemann     Status err = client_socket->Read((void *)&buffer[0], read_size);
39efd065e6SChris Bieneman     if (err.Fail())
40efd065e6SChris Bieneman       abort();
41efd065e6SChris Bieneman     std::string Recv(&buffer[0], read_size);
42efd065e6SChris Bieneman     if (Recv != hello)
43efd065e6SChris Bieneman       abort();
44efd065e6SChris Bieneman     size_t write_size = goodbye.length();
45efd065e6SChris Bieneman     err = client_socket->Write(goodbye.c_str(), write_size);
46efd065e6SChris Bieneman     if (err.Fail())
47efd065e6SChris Bieneman       abort();
48efd065e6SChris Bieneman     if (write_size != goodbye.length())
49efd065e6SChris Bieneman       abort();
50efd065e6SChris Bieneman     delete client_socket;
51efd065e6SChris Bieneman     exit(0);
52efd065e6SChris Bieneman   }
53efd065e6SChris Bieneman }
54efd065e6SChris Bieneman 
TestSocketListen(const char * addr)55efd065e6SChris Bieneman void TestSocketListen(const char *addr) {
5611827799SChris Bieneman   // Skip IPv6 tests if there isn't a valid interafce
5711827799SChris Bieneman   auto addresses = lldb_private::SocketAddress::GetAddressInfo(
5811827799SChris Bieneman       addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
5911827799SChris Bieneman   if (addresses.size() == 0)
6011827799SChris Bieneman     return;
6111827799SChris Bieneman 
6211827799SChris Bieneman   char addr_wrap[256];
6311827799SChris Bieneman   if (addresses.front().GetFamily() == AF_INET6)
6411827799SChris Bieneman     sprintf(addr_wrap, "[%s]", addr);
6511827799SChris Bieneman   else
6611827799SChris Bieneman     sprintf(addr_wrap, "%s", addr);
6711827799SChris Bieneman 
68efd065e6SChris Bieneman   RNBSocket server_socket;
69efd065e6SChris Bieneman   auto result =
7011827799SChris Bieneman       server_socket.Listen(addr, 0, ServerCallbackv4, (const void *)addr_wrap);
71efd065e6SChris Bieneman   ASSERT_TRUE(result == rnb_success);
72efd065e6SChris Bieneman   result = server_socket.Write(hello.c_str(), hello.length());
73efd065e6SChris Bieneman   ASSERT_TRUE(result == rnb_success);
74efd065e6SChris Bieneman   std::string bye;
75efd065e6SChris Bieneman   result = server_socket.Read(bye);
76efd065e6SChris Bieneman   ASSERT_TRUE(result == rnb_success);
77efd065e6SChris Bieneman   ASSERT_EQ(bye, goodbye);
78efd065e6SChris Bieneman 
79efd065e6SChris Bieneman   int exit_status;
80efd065e6SChris Bieneman   wait(&exit_status);
81efd065e6SChris Bieneman   ASSERT_EQ(exit_status, 0);
82efd065e6SChris Bieneman }
83efd065e6SChris Bieneman 
TEST(RNBSocket,LoopBackListenIPv4)84efd065e6SChris Bieneman TEST(RNBSocket, LoopBackListenIPv4) { TestSocketListen("127.0.0.1"); }
85efd065e6SChris Bieneman 
TEST(RNBSocket,LoopBackListenIPv6)8611827799SChris Bieneman TEST(RNBSocket, LoopBackListenIPv6) { TestSocketListen("::1"); }
8711827799SChris Bieneman 
TEST(RNBSocket,AnyListen)887dc58b23SChris Bieneman TEST(RNBSocket, AnyListen) { TestSocketListen("*"); }
897dc58b23SChris Bieneman 
TestSocketConnect(const char * addr)90efd065e6SChris Bieneman void TestSocketConnect(const char *addr) {
9111827799SChris Bieneman   // Skip IPv6 tests if there isn't a valid interafce
9211827799SChris Bieneman   auto addresses = lldb_private::SocketAddress::GetAddressInfo(
9311827799SChris Bieneman       addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
9411827799SChris Bieneman   if (addresses.size() == 0)
9511827799SChris Bieneman     return;
9611827799SChris Bieneman 
97efd065e6SChris Bieneman   char addr_wrap[256];
9811827799SChris Bieneman   if (addresses.front().GetFamily() == AF_INET6)
9911827799SChris Bieneman     sprintf(addr_wrap, "[%s]:0", addr);
10011827799SChris Bieneman   else
101efd065e6SChris Bieneman     sprintf(addr_wrap, "%s:0", addr);
102efd065e6SChris Bieneman 
103efd065e6SChris Bieneman   Socket *server_socket;
104c2fec2fbSRaphael Isemann   llvm::Expected<std::unique_ptr<Socket>> socket_or_err =
105*801cf36aSMichał Górny       Socket::TcpListen(addr_wrap, false);
106c2fec2fbSRaphael Isemann   ASSERT_THAT_EXPECTED(socket_or_err, llvm::Succeeded());
107c2fec2fbSRaphael Isemann   server_socket = socket_or_err->get();
108efd065e6SChris Bieneman 
109efd065e6SChris Bieneman   auto port = ((TCPSocket *)server_socket)->GetLocalPortNumber();
110efd065e6SChris Bieneman   auto child_pid = fork();
111efd065e6SChris Bieneman   if (child_pid != 0) {
112efd065e6SChris Bieneman     RNBSocket client_socket;
113efd065e6SChris Bieneman     auto result = client_socket.Connect(addr, port);
114efd065e6SChris Bieneman     ASSERT_TRUE(result == rnb_success);
115efd065e6SChris Bieneman     result = client_socket.Write(hello.c_str(), hello.length());
116efd065e6SChris Bieneman     ASSERT_TRUE(result == rnb_success);
117efd065e6SChris Bieneman     std::string bye;
118efd065e6SChris Bieneman     result = client_socket.Read(bye);
119efd065e6SChris Bieneman     ASSERT_TRUE(result == rnb_success);
120efd065e6SChris Bieneman     ASSERT_EQ(bye, goodbye);
121efd065e6SChris Bieneman   } else {
122efd065e6SChris Bieneman     Socket *connected_socket;
123c2fec2fbSRaphael Isemann     Status err = server_socket->Accept(connected_socket);
124efd065e6SChris Bieneman     if (err.Fail()) {
125efd065e6SChris Bieneman       llvm::errs() << err.AsCString();
126efd065e6SChris Bieneman       abort();
127efd065e6SChris Bieneman     }
128efd065e6SChris Bieneman     char buffer[32];
129efd065e6SChris Bieneman     size_t read_size = 32;
130efd065e6SChris Bieneman     err = connected_socket->Read((void *)&buffer[0], read_size);
131efd065e6SChris Bieneman     if (err.Fail()) {
132efd065e6SChris Bieneman       llvm::errs() << err.AsCString();
133efd065e6SChris Bieneman       abort();
134efd065e6SChris Bieneman     }
135efd065e6SChris Bieneman     std::string Recv(&buffer[0], read_size);
136efd065e6SChris Bieneman     if (Recv != hello) {
137efd065e6SChris Bieneman       llvm::errs() << err.AsCString();
138efd065e6SChris Bieneman       abort();
139efd065e6SChris Bieneman     }
140efd065e6SChris Bieneman     size_t write_size = goodbye.length();
141efd065e6SChris Bieneman     err = connected_socket->Write(goodbye.c_str(), write_size);
142efd065e6SChris Bieneman     if (err.Fail()) {
143efd065e6SChris Bieneman       llvm::errs() << err.AsCString();
144efd065e6SChris Bieneman       abort();
145efd065e6SChris Bieneman     }
146efd065e6SChris Bieneman     if (write_size != goodbye.length()) {
147efd065e6SChris Bieneman       llvm::errs() << err.AsCString();
148efd065e6SChris Bieneman       abort();
149efd065e6SChris Bieneman     }
150efd065e6SChris Bieneman     exit(0);
151efd065e6SChris Bieneman   }
152efd065e6SChris Bieneman   int exit_status;
153efd065e6SChris Bieneman   wait(&exit_status);
154efd065e6SChris Bieneman   ASSERT_EQ(exit_status, 0);
155efd065e6SChris Bieneman }
156efd065e6SChris Bieneman 
TEST(RNBSocket,LoopBackConnectIPv4)157efd065e6SChris Bieneman TEST(RNBSocket, LoopBackConnectIPv4) { TestSocketConnect("127.0.0.1"); }
15811827799SChris Bieneman 
TEST(RNBSocket,LoopBackConnectIPv6)15911827799SChris Bieneman TEST(RNBSocket, LoopBackConnectIPv6) { TestSocketConnect("::1"); }
160