1//===-- RNBSocketTest.cpp -------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "gtest/gtest.h"
10
11#include <arpa/inet.h>
12#include <sys/sysctl.h>
13#include <unistd.h>
14
15#include "RNBDefs.h"
16#include "RNBSocket.h"
17#include "lldb/Host/Socket.h"
18#include "lldb/Host/common/TCPSocket.h"
19#include "llvm/Testing/Support/Error.h"
20
21using namespace lldb_private;
22
23std::string hello = "Hello, world!";
24std::string goodbye = "Goodbye!";
25
26static void ServerCallbackv4(const void *baton, in_port_t port) {
27 auto child_pid = fork();
28 if (child_pid == 0) {
29 std::string addr_buffer =
30 llvm::formatv(Fmt: "{0}:{1}", Vals: (const char *)baton, Vals&: port).str();
31 llvm::Expected<std::unique_ptr<Socket>> socket_or_err =
32 Socket::TcpConnect(host_and_port: addr_buffer);
33 ASSERT_THAT_EXPECTED(socket_or_err, llvm::Succeeded());
34 Socket *client_socket = socket_or_err->get();
35
36 char buffer[32];
37 size_t read_size = 32;
38 Status err = client_socket->Read(buf: (void *)&buffer[0], num_bytes&: read_size);
39 if (err.Fail())
40 abort();
41 std::string Recv(&buffer[0], read_size);
42 if (Recv != hello)
43 abort();
44 size_t write_size = goodbye.length();
45 err = client_socket->Write(buf: goodbye.c_str(), num_bytes&: write_size);
46 if (err.Fail())
47 abort();
48 if (write_size != goodbye.length())
49 abort();
50 delete client_socket;
51 exit(status: 0);
52 }
53}
54
55void TestSocketListen(const char *addr) {
56 // Skip IPv6 tests if there isn't a valid interafce
57 auto addresses = lldb_private::SocketAddress::GetAddressInfo(
58 hostname: addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
59 if (addresses.size() == 0)
60 return;
61
62 const char *fmt = addresses.front().GetFamily() == AF_INET6 ? "[{0}]" : "{0}";
63 std::string addr_wrap = llvm::formatv(Fmt: fmt, Vals&: addr).str();
64
65 RNBSocket server_socket;
66 auto result = server_socket.Listen(addr, 0, ServerCallbackv4,
67 (const void *)addr_wrap.c_str());
68 ASSERT_TRUE(result == rnb_success);
69 result = server_socket.Write(hello.c_str(), hello.length());
70 ASSERT_TRUE(result == rnb_success);
71 std::string bye;
72 result = server_socket.Read(bye);
73 ASSERT_TRUE(result == rnb_success);
74 ASSERT_EQ(bye, goodbye);
75
76 int exit_status;
77 wait(stat_loc: &exit_status);
78 ASSERT_EQ(exit_status, 0);
79}
80
81TEST(RNBSocket, LoopBackListenIPv4) { TestSocketListen(addr: "127.0.0.1"); }
82
83TEST(RNBSocket, LoopBackListenIPv6) { TestSocketListen(addr: "::1"); }
84
85TEST(RNBSocket, AnyListen) { TestSocketListen(addr: "*"); }
86
87void TestSocketConnect(const char *addr) {
88 // Skip IPv6 tests if there isn't a valid interafce
89 auto addresses = lldb_private::SocketAddress::GetAddressInfo(
90 hostname: addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
91 if (addresses.size() == 0)
92 return;
93
94 const char *fmt =
95 addresses.front().GetFamily() == AF_INET6 ? "[{0}]:0" : "{0}:0";
96 std::string addr_wrap = llvm::formatv(Fmt: fmt, Vals&: addr).str();
97
98 Socket *server_socket;
99 llvm::Expected<std::unique_ptr<Socket>> socket_or_err =
100 Socket::TcpListen(host_and_port: addr_wrap, backlog: false);
101 ASSERT_THAT_EXPECTED(socket_or_err, llvm::Succeeded());
102 server_socket = socket_or_err->get();
103
104 auto port = ((TCPSocket *)server_socket)->GetLocalPortNumber();
105 auto child_pid = fork();
106 if (child_pid != 0) {
107 RNBSocket client_socket;
108 auto result = client_socket.Connect(addr, port);
109 ASSERT_TRUE(result == rnb_success);
110 result = client_socket.Write(hello.c_str(), hello.length());
111 ASSERT_TRUE(result == rnb_success);
112 std::string bye;
113 result = client_socket.Read(bye);
114 ASSERT_TRUE(result == rnb_success);
115 ASSERT_EQ(bye, goodbye);
116 } else {
117 Socket *connected_socket;
118 Status err =
119 server_socket->Accept(timeout: std::chrono::seconds(10), socket&: connected_socket);
120 if (err.Fail()) {
121 llvm::errs() << err.AsCString();
122 abort();
123 }
124 char buffer[32];
125 size_t read_size = 32;
126 err = connected_socket->Read(buf: (void *)&buffer[0], num_bytes&: read_size);
127 if (err.Fail()) {
128 llvm::errs() << err.AsCString();
129 abort();
130 }
131 std::string Recv(&buffer[0], read_size);
132 if (Recv != hello) {
133 llvm::errs() << err.AsCString();
134 abort();
135 }
136 size_t write_size = goodbye.length();
137 err = connected_socket->Write(buf: goodbye.c_str(), num_bytes&: write_size);
138 if (err.Fail()) {
139 llvm::errs() << err.AsCString();
140 abort();
141 }
142 if (write_size != goodbye.length()) {
143 llvm::errs() << err.AsCString();
144 abort();
145 }
146 exit(status: 0);
147 }
148 int exit_status;
149 wait(stat_loc: &exit_status);
150 ASSERT_EQ(exit_status, 0);
151}
152
153TEST(RNBSocket, LoopBackConnectIPv4) { TestSocketConnect(addr: "127.0.0.1"); }
154
155TEST(RNBSocket, LoopBackConnectIPv6) { TestSocketConnect(addr: "::1"); }
156

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of lldb/unittests/debugserver/RNBSocketTest.cpp