Skip to content

Commit 16d3f23

Browse files
committed
Address feedback
- use ::close and ::unlink instead of _close and _unlink on Windows - fix name of raw_socket_stream functions to specify Unix - use \ instead of @ in doxygen comments - write unittest to make sure timeout works correctly
1 parent 4569e17 commit 16d3f23

File tree

3 files changed

+73
-66
lines changed

3 files changed

+73
-66
lines changed

llvm/include/llvm/Support/raw_socket_stream.h

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@ namespace llvm {
2525
class raw_socket_stream;
2626

2727
#ifdef _WIN32
28-
/// @brief Ensures proper initialization and cleanup of winsock resources
28+
/// \brief Ensures proper initialization and cleanup of winsock resources
2929
///
30-
/// @details
3130
/// Make sure that calls to WSAStartup and WSACleanup are balanced.
3231
class WSABalancer {
3332
public:
@@ -36,27 +35,27 @@ class WSABalancer {
3635
};
3736
#endif // _WIN32
3837

39-
/// @class ListeningSocket
40-
/// @brief Manages a passive (i.e., listening) UNIX domain socket
38+
/// \class ListeningSocket
39+
/// \brief Manages a passive (i.e., listening) UNIX domain socket
4140
///
4241
/// The ListeningSocket class encapsulates a UNIX domain socket that can listen
4342
/// and accept incoming connections. ListeningSocket is portable and supports
4443
/// Windows builds begining with Insider Build 17063. ListeningSocket is
45-
/// designed for server-side operations, working alongside raw_socket_streams
44+
/// designed for server-side operations, working alongside \p raw_socket_streams
4645
/// that function as client connections.
4746
///
4847
/// Usage example:
49-
/// @code{.cpp}
48+
/// \code{.cpp}
5049
/// std::string Path = "/path/to/socket"
5150
/// Expected<ListeningSocket> S = ListeningSocket::createListeningSocket(Path);
5251
///
53-
/// if (listeningSocket) {
54-
/// auto connection = S->accept();
55-
/// if (connection) {
56-
/// // Use the accepted raw_socket_stream for communication.
57-
/// }
52+
/// if (S) {
53+
/// Expected<std::unique_ptr<raw_socket_stream>> connection = S->accept();
54+
/// if (connection) {
55+
/// // Use the accepted raw_socket_stream for communication.
56+
/// }
5857
/// }
59-
/// @endcode
58+
/// \endcode
6059
///
6160
class ListeningSocket {
6261
std::atomic<int> FD;
@@ -74,15 +73,15 @@ class ListeningSocket {
7473
ListeningSocket &operator=(const ListeningSocket &) = delete;
7574

7675
/// Closes the socket's FD and unlinks the socket file from the file system.
77-
/// The method is idempotent
76+
/// The method is thread and signal safe
7877
void shutdown();
7978

8079
/// Accepts an incoming connection on the listening socket. This method can
8180
/// optionally either block until a connection is available or timeout after a
8281
/// specified amount of time has passed. By default the method will block
8382
/// until the socket has recieved a connection
8483
///
85-
/// @param Timeout An optional timeout duration in microseconds
84+
/// \param Timeout An optional timeout duration in microseconds
8685
///
8786
Expected<std::unique_ptr<raw_socket_stream>>
8887
accept(std::optional<std::chrono::microseconds> Timeout = std::nullopt);
@@ -91,10 +90,10 @@ class ListeningSocket {
9190
/// Handles the socket creation, binding, and immediately starts listening for
9291
/// incoming connections.
9392
///
94-
/// @param SocketPath The file system path where the socket will be created
95-
/// @param MaxBacklog The max number of connections in a socket's backlog
93+
/// \param SocketPath The file system path where the socket will be created
94+
/// \param MaxBacklog The max number of connections in a socket's backlog
9695
///
97-
static Expected<ListeningSocket> createListeningSocket(
96+
static Expected<ListeningSocket> createListeningUnixSocket(
9897
StringRef SocketPath,
9998
int MaxBacklog = llvm::hardware_concurrency().compute_thread_count());
10099
};
@@ -110,12 +109,11 @@ class raw_socket_stream : public raw_fd_stream {
110109
#endif // _WIN32
111110

112111
public:
113-
// TODO: Should probably be private
114112
raw_socket_stream(int SocketFD);
115-
/// Create a \p raw_socket_stream connected to the Unix domain socket at \p
113+
/// Create a \p raw_socket_stream connected to the UNIX domain socket at \p
116114
/// SocketPath.
117115
static Expected<std::unique_ptr<raw_socket_stream>>
118-
createConnectedSocket(StringRef SocketPath);
116+
createConnectedUnixSocket(StringRef SocketPath);
119117
~raw_socket_stream();
120118
};
121119

llvm/lib/Support/raw_socket_stream.cpp

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -58,24 +58,6 @@ static std::error_code getLastSocketErrorCode() {
5858
#endif
5959
}
6060

61-
static void closeFD(int FD) {
62-
#ifdef _WIN32
63-
// on windows ::close is a deprecated alias for _close
64-
_close(FD);
65-
#else
66-
::close(FD);
67-
#endif
68-
}
69-
70-
static void unlinkFile(StringRef Path) {
71-
#ifdef _WIN32
72-
// on windows ::unlink is a deprecated alias for _unlink
73-
_unlink(Path.str().c_str());
74-
#else
75-
::unlink(Path.str().c_str());
76-
#endif
77-
}
78-
7961
static sockaddr_un setSocketAddr(StringRef SocketPath) {
8062
struct sockaddr_un Addr;
8163
memset(&Addr, 0, sizeof(Addr));
@@ -119,7 +101,8 @@ ListeningSocket::ListeningSocket(ListeningSocket &&LS)
119101
}
120102

121103
Expected<ListeningSocket>
122-
ListeningSocket::createListeningSocket(StringRef SocketPath, int MaxBacklog) {
104+
ListeningSocket::createListeningUnixSocket(StringRef SocketPath,
105+
int MaxBacklog) {
123106

124107
// Handle instances where the target socket address already exists and
125108
// differentiate between a preexisting file with and without a bound socket
@@ -132,14 +115,14 @@ ListeningSocket::createListeningSocket(StringRef SocketPath, int MaxBacklog) {
132115
if (!MaybeFD) {
133116

134117
// Regardless of the error, notify the caller that a file already exists
135-
// at the desired socket address. The file must be removed before ::bind
136-
// can use the socket address
118+
// at the desired socket address and that there is no bound socket at that
119+
// address. The file must be removed before ::bind can use the address
137120
consumeError(MaybeFD.takeError());
138121
return llvm::make_error<StringError>(
139122
std::make_error_code(std::errc::file_exists),
140123
"Socket address unavailable");
141124
}
142-
closeFD(std::move(*MaybeFD));
125+
::close(std::move(*MaybeFD));
143126

144127
// Notify caller that the provided socket address already has a bound socket
145128
return llvm::make_error<StringError>(
@@ -184,31 +167,28 @@ ListeningSocket::createListeningSocket(StringRef SocketPath, int MaxBacklog) {
184167
Expected<std::unique_ptr<raw_socket_stream>>
185168
ListeningSocket::accept(std::optional<std::chrono::microseconds> Timeout) {
186169

187-
int SelectStatus;
188-
int AcceptFD;
189-
170+
fd_set Readfds;
171+
FD_ZERO(&Readfds);
190172
#ifdef _WIN32
191173
SOCKET WinServerSock = _get_osfhandle(FD);
174+
FD_SET(WinServerSock, &Readfds);
175+
#else
176+
FD_SET(FD, &Readfds);
192177
#endif
193178

194-
fd_set Readfds;
179+
int SelectStatus;
195180
if (Timeout.has_value()) {
196181
timeval TV = {0, Timeout.value().count()};
197-
FD_ZERO(&Readfds);
198-
#ifdef _WIN32
199-
FD_SET(WinServerSock, &Readfds);
200-
#else
201-
FD_SET(FD, &Readfds);
202-
#endif
203182
SelectStatus = ::select(FD + 1, &Readfds, NULL, NULL, &TV);
204183
} else {
205-
SelectStatus = 1;
184+
SelectStatus = ::select(FD + 1, &Readfds, NULL, NULL, NULL);
206185
}
207186

208187
if (SelectStatus == -1)
209188
return llvm::make_error<StringError>(getLastSocketErrorCode(),
210-
"Select failed");
189+
"select failed");
211190

191+
int AcceptFD;
212192
if (SelectStatus) {
213193
#ifdef _WIN32
214194
SOCKET WinAcceptSock = ::accept(WinServerSock, NULL, NULL);
@@ -218,20 +198,20 @@ ListeningSocket::accept(std::optional<std::chrono::microseconds> Timeout) {
218198
#endif
219199
} else
220200
return llvm::make_error<StringError>(
221-
std::make_error_code(std::errc::timed_out), "Accept timed out");
201+
std::make_error_code(std::errc::timed_out), "accept timed out");
222202

223203
if (AcceptFD == -1)
224204
return llvm::make_error<StringError>(getLastSocketErrorCode(),
225-
"Accept failed");
205+
"accept failed");
226206

227207
return std::make_unique<raw_socket_stream>(AcceptFD);
228208
}
229209

230210
void ListeningSocket::shutdown() {
231211
if (FD == -1)
232212
return;
233-
closeFD(FD);
234-
unlinkFile(SocketPath);
213+
::close(FD);
214+
::unlink(SocketPath.c_str());
235215
FD = -1;
236216
}
237217

@@ -245,7 +225,7 @@ raw_socket_stream::raw_socket_stream(int SocketFD)
245225
: raw_fd_stream(SocketFD, true) {}
246226

247227
Expected<std::unique_ptr<raw_socket_stream>>
248-
raw_socket_stream::createConnectedSocket(StringRef SocketPath) {
228+
raw_socket_stream::createConnectedUnixSocket(StringRef SocketPath) {
249229
#ifdef _WIN32
250230
WSABalancer _;
251231
#endif // _WIN32

llvm/unittests/Support/raw_socket_stream_test.cpp

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,19 @@ TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) {
3232
GTEST_SKIP();
3333

3434
SmallString<100> SocketPath;
35-
llvm::sys::fs::createUniquePath("test_raw_socket_stream.sock", SocketPath,
36-
true);
35+
llvm::sys::fs::createUniquePath("client_server_comms.sock", SocketPath, true);
3736

3837
// Make sure socket file does not exist. May still be there from the last test
3938
std::remove(SocketPath.c_str());
4039

41-
char Bytes[8];
42-
4340
Expected<ListeningSocket> MaybeServerListener =
44-
ListeningSocket::createListeningSocket(SocketPath);
41+
ListeningSocket::createListeningUnixSocket(SocketPath);
4542
ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
4643

4744
ListeningSocket ServerListener = std::move(*MaybeServerListener);
4845

4946
Expected<std::unique_ptr<raw_socket_stream>> MaybeClient =
50-
raw_socket_stream::createConnectedSocket(SocketPath);
47+
raw_socket_stream::createConnectedUnixSocket(SocketPath);
5148
ASSERT_THAT_EXPECTED(MaybeClient, llvm::Succeeded());
5249

5350
raw_socket_stream &Client = **MaybeClient;
@@ -61,11 +58,43 @@ TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) {
6158
Client << "01234567";
6259
Client.flush();
6360

61+
char Bytes[8];
6462
ssize_t BytesRead = Server.read(Bytes, 8);
6563

6664
std::string string(Bytes, 8);
6765

6866
ASSERT_EQ(8, BytesRead);
6967
ASSERT_EQ("01234567", string);
7068
}
71-
} // namespace
69+
70+
TEST(raw_socket_streamTest, TIMEOUT_PROVIDED) {
71+
if (!hasUnixSocketSupport())
72+
GTEST_SKIP();
73+
74+
SmallString<100> SocketPath;
75+
llvm::sys::fs::createUniquePath("timout_provided.sock", SocketPath, true);
76+
77+
// Make sure socket file does not exist. May still be there from the last test
78+
std::remove(SocketPath.c_str());
79+
80+
Expected<ListeningSocket> MaybeServerListener =
81+
ListeningSocket::createListeningUnixSocket(SocketPath);
82+
ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
83+
ListeningSocket ServerListener = std::move(*MaybeServerListener);
84+
85+
std::chrono::seconds Timeout = std::chrono::seconds(5);
86+
auto Start = std::chrono::steady_clock::now();
87+
Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
88+
ServerListener.accept(Timeout);
89+
auto End = std::chrono::steady_clock::now();
90+
auto Duration = std::chrono::duration_cast<std::chrono::seconds>(End - Start);
91+
ASSERT_NEAR(Duration.count(), Timeout.count(), 1);
92+
93+
ASSERT_THAT_EXPECTED(MaybeServer, Failed());
94+
llvm::Error Err = MaybeServer.takeError();
95+
llvm::handleAllErrors(std::move(Err), [&](const llvm::StringError &SE) {
96+
std::error_code EC = SE.convertToErrorCode();
97+
ASSERT_EQ(EC, std::errc::timed_out);
98+
});
99+
}
100+
} // namespace

0 commit comments

Comments
 (0)