1 | #include "llvm/ADT/SmallString.h" |
2 | #include "llvm/Config/llvm-config.h" |
3 | #include "llvm/Support/Casting.h" |
4 | #include "llvm/Support/FileSystem.h" |
5 | #include "llvm/Support/FileUtilities.h" |
6 | #include "llvm/Support/raw_socket_stream.h" |
7 | #include "llvm/Testing/Support/Error.h" |
8 | #include "gtest/gtest.h" |
9 | #include <future> |
10 | #include <iostream> |
11 | #include <stdlib.h> |
12 | #include <thread> |
13 | |
14 | #ifdef _WIN32 |
15 | #include "llvm/Support/Windows/WindowsSupport.h" |
16 | #endif |
17 | |
18 | using namespace llvm; |
19 | |
20 | namespace { |
21 | |
22 | bool hasUnixSocketSupport() { |
23 | #ifdef _WIN32 |
24 | VersionTuple Ver = GetWindowsOSVersion(); |
25 | if (Ver < VersionTuple(10, 0, 0, 17063)) |
26 | return false; |
27 | #endif |
28 | return true; |
29 | } |
30 | |
31 | TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) { |
32 | if (!hasUnixSocketSupport()) |
33 | GTEST_SKIP(); |
34 | |
35 | SmallString<100> SocketPath; |
36 | llvm::sys::fs::createUniquePath(Model: "client_server_comms.sock" , ResultPath&: SocketPath, MakeAbsolute: true); |
37 | |
38 | // Make sure socket file does not exist. May still be there from the last test |
39 | std::remove(filename: SocketPath.c_str()); |
40 | |
41 | Expected<ListeningSocket> MaybeServerListener = |
42 | ListeningSocket::createUnix(SocketPath); |
43 | ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded()); |
44 | |
45 | ListeningSocket ServerListener = std::move(*MaybeServerListener); |
46 | |
47 | Expected<std::unique_ptr<raw_socket_stream>> MaybeClient = |
48 | raw_socket_stream::createConnectedUnix(SocketPath); |
49 | ASSERT_THAT_EXPECTED(MaybeClient, llvm::Succeeded()); |
50 | |
51 | raw_socket_stream &Client = **MaybeClient; |
52 | |
53 | Expected<std::unique_ptr<raw_socket_stream>> MaybeServer = |
54 | ServerListener.accept(); |
55 | ASSERT_THAT_EXPECTED(MaybeServer, llvm::Succeeded()); |
56 | |
57 | raw_socket_stream &Server = **MaybeServer; |
58 | |
59 | Client << "01234567" ; |
60 | Client.flush(); |
61 | |
62 | char Bytes[8]; |
63 | ssize_t BytesRead = Server.read(Ptr: Bytes, Size: 8); |
64 | |
65 | std::string string(Bytes, 8); |
66 | |
67 | ASSERT_EQ(8, BytesRead); |
68 | ASSERT_EQ("01234567" , string); |
69 | } |
70 | |
71 | TEST(raw_socket_streamTest, TIMEOUT_PROVIDED) { |
72 | if (!hasUnixSocketSupport()) |
73 | GTEST_SKIP(); |
74 | |
75 | SmallString<100> SocketPath; |
76 | llvm::sys::fs::createUniquePath(Model: "timout_provided.sock" , ResultPath&: SocketPath, MakeAbsolute: true); |
77 | |
78 | // Make sure socket file does not exist. May still be there from the last test |
79 | std::remove(filename: SocketPath.c_str()); |
80 | |
81 | Expected<ListeningSocket> MaybeServerListener = |
82 | ListeningSocket::createUnix(SocketPath); |
83 | ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded()); |
84 | ListeningSocket ServerListener = std::move(*MaybeServerListener); |
85 | |
86 | std::chrono::milliseconds Timeout = std::chrono::milliseconds(100); |
87 | Expected<std::unique_ptr<raw_socket_stream>> MaybeServer = |
88 | ServerListener.accept(Timeout); |
89 | |
90 | ASSERT_THAT_EXPECTED(MaybeServer, Failed()); |
91 | llvm::Error Err = MaybeServer.takeError(); |
92 | llvm::handleAllErrors(E: std::move(Err), Handlers: [&](const llvm::StringError &SE) { |
93 | std::error_code EC = SE.convertToErrorCode(); |
94 | ASSERT_EQ(EC, std::errc::timed_out); |
95 | }); |
96 | } |
97 | |
98 | TEST(raw_socket_streamTest, FILE_DESCRIPTOR_CLOSED) { |
99 | if (!hasUnixSocketSupport()) |
100 | GTEST_SKIP(); |
101 | |
102 | SmallString<100> SocketPath; |
103 | llvm::sys::fs::createUniquePath(Model: "fd_closed.sock" , ResultPath&: SocketPath, MakeAbsolute: true); |
104 | |
105 | // Make sure socket file does not exist. May still be there from the last test |
106 | std::remove(filename: SocketPath.c_str()); |
107 | |
108 | Expected<ListeningSocket> MaybeServerListener = |
109 | ListeningSocket::createUnix(SocketPath); |
110 | ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded()); |
111 | ListeningSocket ServerListener = std::move(*MaybeServerListener); |
112 | |
113 | // Create a separate thread to close the socket after a delay. Simulates a |
114 | // signal handler calling ServerListener::shutdown |
115 | std::thread CloseThread([&]() { |
116 | std::this_thread::sleep_for(rtime: std::chrono::milliseconds(500)); |
117 | ServerListener.shutdown(); |
118 | }); |
119 | |
120 | Expected<std::unique_ptr<raw_socket_stream>> MaybeServer = |
121 | ServerListener.accept(); |
122 | |
123 | // Wait for the CloseThread to finish |
124 | CloseThread.join(); |
125 | |
126 | ASSERT_THAT_EXPECTED(MaybeServer, Failed()); |
127 | llvm::Error Err = MaybeServer.takeError(); |
128 | llvm::handleAllErrors(E: std::move(Err), Handlers: [&](const llvm::StringError &SE) { |
129 | std::error_code EC = SE.convertToErrorCode(); |
130 | ASSERT_EQ(EC, std::errc::operation_canceled); |
131 | }); |
132 | } |
133 | } // namespace |
134 | |