1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/socket_stream.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #if defined(_WIN32) && _WIN32
18*61c4878aSAndroid Build Coastguard Worker #include <fcntl.h>
19*61c4878aSAndroid Build Coastguard Worker #include <io.h>
20*61c4878aSAndroid Build Coastguard Worker #include <winsock2.h>
21*61c4878aSAndroid Build Coastguard Worker #include <ws2tcpip.h>
22*61c4878aSAndroid Build Coastguard Worker #define SHUT_RDWR SD_BOTH
23*61c4878aSAndroid Build Coastguard Worker #else
24*61c4878aSAndroid Build Coastguard Worker #include <arpa/inet.h>
25*61c4878aSAndroid Build Coastguard Worker #include <netdb.h>
26*61c4878aSAndroid Build Coastguard Worker #include <netinet/in.h>
27*61c4878aSAndroid Build Coastguard Worker #include <poll.h>
28*61c4878aSAndroid Build Coastguard Worker #include <sys/socket.h>
29*61c4878aSAndroid Build Coastguard Worker #include <sys/types.h>
30*61c4878aSAndroid Build Coastguard Worker #include <unistd.h>
31*61c4878aSAndroid Build Coastguard Worker #endif // defined(_WIN32) && _WIN32
32*61c4878aSAndroid Build Coastguard Worker
33*61c4878aSAndroid Build Coastguard Worker #include <cerrno>
34*61c4878aSAndroid Build Coastguard Worker #include <cstring>
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
37*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
38*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h"
39*61c4878aSAndroid Build Coastguard Worker #include "pw_string/to_string.h"
40*61c4878aSAndroid Build Coastguard Worker
41*61c4878aSAndroid Build Coastguard Worker namespace pw::stream {
42*61c4878aSAndroid Build Coastguard Worker namespace {
43*61c4878aSAndroid Build Coastguard Worker
44*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kServerBacklogLength = 1;
45*61c4878aSAndroid Build Coastguard Worker constexpr const char* kLocalhostAddress = "localhost";
46*61c4878aSAndroid Build Coastguard Worker
47*61c4878aSAndroid Build Coastguard Worker // Set necessary options on a socket file descriptor.
ConfigureSocket(int socket)48*61c4878aSAndroid Build Coastguard Worker void ConfigureSocket([[maybe_unused]] int socket) {
49*61c4878aSAndroid Build Coastguard Worker #if defined(__APPLE__)
50*61c4878aSAndroid Build Coastguard Worker // Use SO_NOSIGPIPE to avoid getting a SIGPIPE signal when the remote peer
51*61c4878aSAndroid Build Coastguard Worker // drops the connection. This is supported on macOS only.
52*61c4878aSAndroid Build Coastguard Worker constexpr int value = 1;
53*61c4878aSAndroid Build Coastguard Worker if (setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(int)) < 0) {
54*61c4878aSAndroid Build Coastguard Worker PW_LOG_WARN("Failed to set SO_NOSIGPIPE: %s", std::strerror(errno));
55*61c4878aSAndroid Build Coastguard Worker }
56*61c4878aSAndroid Build Coastguard Worker #endif // defined(__APPLE__)
57*61c4878aSAndroid Build Coastguard Worker }
58*61c4878aSAndroid Build Coastguard Worker
59*61c4878aSAndroid Build Coastguard Worker #if defined(_WIN32) && _WIN32
close(SOCKET s)60*61c4878aSAndroid Build Coastguard Worker int close(SOCKET s) { return closesocket(s); }
61*61c4878aSAndroid Build Coastguard Worker
write(int fd,const void * buf,size_t count)62*61c4878aSAndroid Build Coastguard Worker ssize_t write(int fd, const void* buf, size_t count) {
63*61c4878aSAndroid Build Coastguard Worker return _write(fd, buf, count);
64*61c4878aSAndroid Build Coastguard Worker }
65*61c4878aSAndroid Build Coastguard Worker
poll(struct pollfd * fds,unsigned int nfds,int timeout)66*61c4878aSAndroid Build Coastguard Worker int poll(struct pollfd* fds, unsigned int nfds, int timeout) {
67*61c4878aSAndroid Build Coastguard Worker return WSAPoll(fds, nfds, timeout);
68*61c4878aSAndroid Build Coastguard Worker }
69*61c4878aSAndroid Build Coastguard Worker
pipe(int pipefd[2])70*61c4878aSAndroid Build Coastguard Worker int pipe(int pipefd[2]) { return _pipe(pipefd, 256, O_BINARY); }
71*61c4878aSAndroid Build Coastguard Worker
setsockopt(int fd,int level,int optname,const void * optval,unsigned int optlen)72*61c4878aSAndroid Build Coastguard Worker int setsockopt(
73*61c4878aSAndroid Build Coastguard Worker int fd, int level, int optname, const void* optval, unsigned int optlen) {
74*61c4878aSAndroid Build Coastguard Worker return setsockopt(static_cast<SOCKET>(fd),
75*61c4878aSAndroid Build Coastguard Worker level,
76*61c4878aSAndroid Build Coastguard Worker optname,
77*61c4878aSAndroid Build Coastguard Worker static_cast<const char*>(optval),
78*61c4878aSAndroid Build Coastguard Worker static_cast<int>(optlen));
79*61c4878aSAndroid Build Coastguard Worker }
80*61c4878aSAndroid Build Coastguard Worker
81*61c4878aSAndroid Build Coastguard Worker class WinsockInitializer {
82*61c4878aSAndroid Build Coastguard Worker public:
WinsockInitializer()83*61c4878aSAndroid Build Coastguard Worker WinsockInitializer() {
84*61c4878aSAndroid Build Coastguard Worker WSADATA data = {};
85*61c4878aSAndroid Build Coastguard Worker PW_CHECK_INT_EQ(
86*61c4878aSAndroid Build Coastguard Worker WSAStartup(MAKEWORD(2, 2), &data), 0, "Failed to initialize winsock");
87*61c4878aSAndroid Build Coastguard Worker }
~WinsockInitializer()88*61c4878aSAndroid Build Coastguard Worker ~WinsockInitializer() {
89*61c4878aSAndroid Build Coastguard Worker // TODO: b/301545011 - This currently fails, probably a cleanup race.
90*61c4878aSAndroid Build Coastguard Worker WSACleanup();
91*61c4878aSAndroid Build Coastguard Worker }
92*61c4878aSAndroid Build Coastguard Worker };
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker [[maybe_unused]] WinsockInitializer initializer;
95*61c4878aSAndroid Build Coastguard Worker
96*61c4878aSAndroid Build Coastguard Worker #endif // defined(_WIN32) && _WIN32
97*61c4878aSAndroid Build Coastguard Worker
98*61c4878aSAndroid Build Coastguard Worker } // namespace
99*61c4878aSAndroid Build Coastguard Worker
Connect(const char * host,uint16_t port)100*61c4878aSAndroid Build Coastguard Worker Status SocketStream::SocketStream::Connect(const char* host, uint16_t port) {
101*61c4878aSAndroid Build Coastguard Worker if (host == nullptr) {
102*61c4878aSAndroid Build Coastguard Worker host = kLocalhostAddress;
103*61c4878aSAndroid Build Coastguard Worker }
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker struct addrinfo hints = {};
106*61c4878aSAndroid Build Coastguard Worker struct addrinfo* res;
107*61c4878aSAndroid Build Coastguard Worker char port_buffer[6];
108*61c4878aSAndroid Build Coastguard Worker PW_CHECK(ToString(port, port_buffer).ok());
109*61c4878aSAndroid Build Coastguard Worker hints.ai_family = AF_UNSPEC;
110*61c4878aSAndroid Build Coastguard Worker hints.ai_socktype = SOCK_STREAM;
111*61c4878aSAndroid Build Coastguard Worker hints.ai_flags = AI_NUMERICSERV;
112*61c4878aSAndroid Build Coastguard Worker if (getaddrinfo(host, port_buffer, &hints, &res) != 0) {
113*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR("Failed to configure connection address for socket");
114*61c4878aSAndroid Build Coastguard Worker return Status::InvalidArgument();
115*61c4878aSAndroid Build Coastguard Worker }
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard Worker struct addrinfo* rp;
118*61c4878aSAndroid Build Coastguard Worker int connection_fd;
119*61c4878aSAndroid Build Coastguard Worker for (rp = res; rp != nullptr; rp = rp->ai_next) {
120*61c4878aSAndroid Build Coastguard Worker connection_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
121*61c4878aSAndroid Build Coastguard Worker if (connection_fd != kInvalidFd) {
122*61c4878aSAndroid Build Coastguard Worker break;
123*61c4878aSAndroid Build Coastguard Worker }
124*61c4878aSAndroid Build Coastguard Worker }
125*61c4878aSAndroid Build Coastguard Worker
126*61c4878aSAndroid Build Coastguard Worker if (connection_fd == kInvalidFd) {
127*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR("Failed to create a socket: %s", std::strerror(errno));
128*61c4878aSAndroid Build Coastguard Worker freeaddrinfo(res);
129*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
130*61c4878aSAndroid Build Coastguard Worker }
131*61c4878aSAndroid Build Coastguard Worker
132*61c4878aSAndroid Build Coastguard Worker ConfigureSocket(connection_fd);
133*61c4878aSAndroid Build Coastguard Worker if (connect(connection_fd, rp->ai_addr, rp->ai_addrlen) == -1) {
134*61c4878aSAndroid Build Coastguard Worker close(connection_fd);
135*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR(
136*61c4878aSAndroid Build Coastguard Worker "Failed to connect to %s:%d: %s", host, port, std::strerror(errno));
137*61c4878aSAndroid Build Coastguard Worker freeaddrinfo(res);
138*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
139*61c4878aSAndroid Build Coastguard Worker }
140*61c4878aSAndroid Build Coastguard Worker
141*61c4878aSAndroid Build Coastguard Worker // Mark as ready and take ownership of the connection by this object.
142*61c4878aSAndroid Build Coastguard Worker {
143*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(connection_mutex_);
144*61c4878aSAndroid Build Coastguard Worker connection_fd_ = connection_fd;
145*61c4878aSAndroid Build Coastguard Worker TakeConnectionWithLockHeld();
146*61c4878aSAndroid Build Coastguard Worker ready_ = true;
147*61c4878aSAndroid Build Coastguard Worker }
148*61c4878aSAndroid Build Coastguard Worker
149*61c4878aSAndroid Build Coastguard Worker freeaddrinfo(res);
150*61c4878aSAndroid Build Coastguard Worker return OkStatus();
151*61c4878aSAndroid Build Coastguard Worker }
152*61c4878aSAndroid Build Coastguard Worker
153*61c4878aSAndroid Build Coastguard Worker // Configures socket options.
SetSockOpt(int level,int optname,const void * optval,unsigned int optlen)154*61c4878aSAndroid Build Coastguard Worker int SocketStream::SetSockOpt(int level,
155*61c4878aSAndroid Build Coastguard Worker int optname,
156*61c4878aSAndroid Build Coastguard Worker const void* optval,
157*61c4878aSAndroid Build Coastguard Worker unsigned int optlen) {
158*61c4878aSAndroid Build Coastguard Worker ConnectionOwnership ownership(this);
159*61c4878aSAndroid Build Coastguard Worker if (ownership.fd() == kInvalidFd) {
160*61c4878aSAndroid Build Coastguard Worker return EBADF;
161*61c4878aSAndroid Build Coastguard Worker }
162*61c4878aSAndroid Build Coastguard Worker return setsockopt(ownership.fd(), level, optname, optval, optlen);
163*61c4878aSAndroid Build Coastguard Worker }
164*61c4878aSAndroid Build Coastguard Worker
Close()165*61c4878aSAndroid Build Coastguard Worker void SocketStream::Close() {
166*61c4878aSAndroid Build Coastguard Worker ConnectionOwnership ownership(this);
167*61c4878aSAndroid Build Coastguard Worker {
168*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(connection_mutex_);
169*61c4878aSAndroid Build Coastguard Worker if (ready_) {
170*61c4878aSAndroid Build Coastguard Worker // Shutdown the connection and send tear down notification to unblock any
171*61c4878aSAndroid Build Coastguard Worker // waiters.
172*61c4878aSAndroid Build Coastguard Worker if (connection_fd_ != kInvalidFd) {
173*61c4878aSAndroid Build Coastguard Worker shutdown(connection_fd_, SHUT_RDWR);
174*61c4878aSAndroid Build Coastguard Worker }
175*61c4878aSAndroid Build Coastguard Worker if (connection_pipe_w_fd_ != kInvalidFd) {
176*61c4878aSAndroid Build Coastguard Worker write(connection_pipe_w_fd_, "T", 1);
177*61c4878aSAndroid Build Coastguard Worker }
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard Worker // Release ownership of the connection by this object and mark as no
180*61c4878aSAndroid Build Coastguard Worker // longer ready.
181*61c4878aSAndroid Build Coastguard Worker ReleaseConnectionWithLockHeld();
182*61c4878aSAndroid Build Coastguard Worker ready_ = false;
183*61c4878aSAndroid Build Coastguard Worker }
184*61c4878aSAndroid Build Coastguard Worker }
185*61c4878aSAndroid Build Coastguard Worker }
186*61c4878aSAndroid Build Coastguard Worker
DoWrite(span<const std::byte> data)187*61c4878aSAndroid Build Coastguard Worker Status SocketStream::DoWrite(span<const std::byte> data) {
188*61c4878aSAndroid Build Coastguard Worker int send_flags = 0;
189*61c4878aSAndroid Build Coastguard Worker #if defined(__linux__)
190*61c4878aSAndroid Build Coastguard Worker // Use MSG_NOSIGNAL to avoid getting a SIGPIPE signal when the remote
191*61c4878aSAndroid Build Coastguard Worker // peer drops the connection. This is supported on Linux only.
192*61c4878aSAndroid Build Coastguard Worker send_flags |= MSG_NOSIGNAL;
193*61c4878aSAndroid Build Coastguard Worker #endif // defined(__linux__)
194*61c4878aSAndroid Build Coastguard Worker
195*61c4878aSAndroid Build Coastguard Worker ssize_t bytes_sent;
196*61c4878aSAndroid Build Coastguard Worker {
197*61c4878aSAndroid Build Coastguard Worker ConnectionOwnership ownership(this);
198*61c4878aSAndroid Build Coastguard Worker if (ownership.fd() == kInvalidFd) {
199*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
200*61c4878aSAndroid Build Coastguard Worker }
201*61c4878aSAndroid Build Coastguard Worker bytes_sent = send(ownership.fd(),
202*61c4878aSAndroid Build Coastguard Worker reinterpret_cast<const char*>(data.data()),
203*61c4878aSAndroid Build Coastguard Worker data.size_bytes(),
204*61c4878aSAndroid Build Coastguard Worker send_flags);
205*61c4878aSAndroid Build Coastguard Worker }
206*61c4878aSAndroid Build Coastguard Worker
207*61c4878aSAndroid Build Coastguard Worker if (bytes_sent < 0 || static_cast<size_t>(bytes_sent) != data.size()) {
208*61c4878aSAndroid Build Coastguard Worker if (errno == EPIPE) {
209*61c4878aSAndroid Build Coastguard Worker // An EPIPE indicates that the connection is closed. Return an OutOfRange
210*61c4878aSAndroid Build Coastguard Worker // error.
211*61c4878aSAndroid Build Coastguard Worker return Status::OutOfRange();
212*61c4878aSAndroid Build Coastguard Worker }
213*61c4878aSAndroid Build Coastguard Worker
214*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
215*61c4878aSAndroid Build Coastguard Worker }
216*61c4878aSAndroid Build Coastguard Worker return OkStatus();
217*61c4878aSAndroid Build Coastguard Worker }
218*61c4878aSAndroid Build Coastguard Worker
DoRead(ByteSpan dest)219*61c4878aSAndroid Build Coastguard Worker StatusWithSize SocketStream::DoRead(ByteSpan dest) {
220*61c4878aSAndroid Build Coastguard Worker ConnectionOwnership ownership(this);
221*61c4878aSAndroid Build Coastguard Worker if (ownership.fd() == kInvalidFd) {
222*61c4878aSAndroid Build Coastguard Worker return StatusWithSize::Unknown();
223*61c4878aSAndroid Build Coastguard Worker }
224*61c4878aSAndroid Build Coastguard Worker
225*61c4878aSAndroid Build Coastguard Worker // Wait for data to read or a tear down notification.
226*61c4878aSAndroid Build Coastguard Worker pollfd fds_to_poll[2];
227*61c4878aSAndroid Build Coastguard Worker fds_to_poll[0].fd = ownership.fd();
228*61c4878aSAndroid Build Coastguard Worker fds_to_poll[0].events = POLLIN | POLLERR | POLLHUP;
229*61c4878aSAndroid Build Coastguard Worker fds_to_poll[1].fd = ownership.pipe_r_fd();
230*61c4878aSAndroid Build Coastguard Worker fds_to_poll[1].events = POLLIN;
231*61c4878aSAndroid Build Coastguard Worker poll(fds_to_poll, 2, -1);
232*61c4878aSAndroid Build Coastguard Worker if (!(fds_to_poll[0].revents & POLLIN)) {
233*61c4878aSAndroid Build Coastguard Worker return StatusWithSize::Unknown();
234*61c4878aSAndroid Build Coastguard Worker }
235*61c4878aSAndroid Build Coastguard Worker
236*61c4878aSAndroid Build Coastguard Worker ssize_t bytes_rcvd = recv(ownership.fd(),
237*61c4878aSAndroid Build Coastguard Worker reinterpret_cast<char*>(dest.data()),
238*61c4878aSAndroid Build Coastguard Worker dest.size_bytes(),
239*61c4878aSAndroid Build Coastguard Worker 0);
240*61c4878aSAndroid Build Coastguard Worker if (bytes_rcvd == 0) {
241*61c4878aSAndroid Build Coastguard Worker // Remote peer has closed the connection.
242*61c4878aSAndroid Build Coastguard Worker Close();
243*61c4878aSAndroid Build Coastguard Worker return StatusWithSize::OutOfRange();
244*61c4878aSAndroid Build Coastguard Worker } else if (bytes_rcvd < 0) {
245*61c4878aSAndroid Build Coastguard Worker if (errno == EAGAIN || errno == EWOULDBLOCK) {
246*61c4878aSAndroid Build Coastguard Worker // Socket timed out when trying to read.
247*61c4878aSAndroid Build Coastguard Worker // This should only occur if SO_RCVTIMEO was configured to be nonzero, or
248*61c4878aSAndroid Build Coastguard Worker // if the socket was opened with the O_NONBLOCK flag to prevent any
249*61c4878aSAndroid Build Coastguard Worker // blocking when performing reads or writes.
250*61c4878aSAndroid Build Coastguard Worker return StatusWithSize::ResourceExhausted();
251*61c4878aSAndroid Build Coastguard Worker }
252*61c4878aSAndroid Build Coastguard Worker return StatusWithSize::Unknown();
253*61c4878aSAndroid Build Coastguard Worker }
254*61c4878aSAndroid Build Coastguard Worker return StatusWithSize(bytes_rcvd);
255*61c4878aSAndroid Build Coastguard Worker }
256*61c4878aSAndroid Build Coastguard Worker
TakeConnection()257*61c4878aSAndroid Build Coastguard Worker int SocketStream::TakeConnection() {
258*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(connection_mutex_);
259*61c4878aSAndroid Build Coastguard Worker return TakeConnectionWithLockHeld();
260*61c4878aSAndroid Build Coastguard Worker }
261*61c4878aSAndroid Build Coastguard Worker
TakeConnectionWithLockHeld()262*61c4878aSAndroid Build Coastguard Worker int SocketStream::TakeConnectionWithLockHeld() {
263*61c4878aSAndroid Build Coastguard Worker ++connection_own_count_;
264*61c4878aSAndroid Build Coastguard Worker
265*61c4878aSAndroid Build Coastguard Worker if (ready_ && (connection_fd_ != kInvalidFd) &&
266*61c4878aSAndroid Build Coastguard Worker (connection_pipe_r_fd_ == kInvalidFd)) {
267*61c4878aSAndroid Build Coastguard Worker int fd_list[2];
268*61c4878aSAndroid Build Coastguard Worker if (pipe(fd_list) >= 0) {
269*61c4878aSAndroid Build Coastguard Worker connection_pipe_r_fd_ = fd_list[0];
270*61c4878aSAndroid Build Coastguard Worker connection_pipe_w_fd_ = fd_list[1];
271*61c4878aSAndroid Build Coastguard Worker }
272*61c4878aSAndroid Build Coastguard Worker }
273*61c4878aSAndroid Build Coastguard Worker
274*61c4878aSAndroid Build Coastguard Worker if (!ready_ || (connection_pipe_r_fd_ == kInvalidFd) ||
275*61c4878aSAndroid Build Coastguard Worker (connection_pipe_w_fd_ == kInvalidFd)) {
276*61c4878aSAndroid Build Coastguard Worker return kInvalidFd;
277*61c4878aSAndroid Build Coastguard Worker }
278*61c4878aSAndroid Build Coastguard Worker return connection_fd_;
279*61c4878aSAndroid Build Coastguard Worker }
280*61c4878aSAndroid Build Coastguard Worker
ReleaseConnection()281*61c4878aSAndroid Build Coastguard Worker void SocketStream::ReleaseConnection() {
282*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(connection_mutex_);
283*61c4878aSAndroid Build Coastguard Worker ReleaseConnectionWithLockHeld();
284*61c4878aSAndroid Build Coastguard Worker }
285*61c4878aSAndroid Build Coastguard Worker
ReleaseConnectionWithLockHeld()286*61c4878aSAndroid Build Coastguard Worker void SocketStream::ReleaseConnectionWithLockHeld() {
287*61c4878aSAndroid Build Coastguard Worker --connection_own_count_;
288*61c4878aSAndroid Build Coastguard Worker
289*61c4878aSAndroid Build Coastguard Worker if (connection_own_count_ <= 0) {
290*61c4878aSAndroid Build Coastguard Worker ready_ = false;
291*61c4878aSAndroid Build Coastguard Worker if (connection_fd_ != kInvalidFd) {
292*61c4878aSAndroid Build Coastguard Worker close(connection_fd_);
293*61c4878aSAndroid Build Coastguard Worker connection_fd_ = kInvalidFd;
294*61c4878aSAndroid Build Coastguard Worker }
295*61c4878aSAndroid Build Coastguard Worker if (connection_pipe_r_fd_ != kInvalidFd) {
296*61c4878aSAndroid Build Coastguard Worker close(connection_pipe_r_fd_);
297*61c4878aSAndroid Build Coastguard Worker connection_pipe_r_fd_ = kInvalidFd;
298*61c4878aSAndroid Build Coastguard Worker }
299*61c4878aSAndroid Build Coastguard Worker if (connection_pipe_w_fd_ != kInvalidFd) {
300*61c4878aSAndroid Build Coastguard Worker close(connection_pipe_w_fd_);
301*61c4878aSAndroid Build Coastguard Worker connection_pipe_w_fd_ = kInvalidFd;
302*61c4878aSAndroid Build Coastguard Worker }
303*61c4878aSAndroid Build Coastguard Worker }
304*61c4878aSAndroid Build Coastguard Worker }
305*61c4878aSAndroid Build Coastguard Worker
306*61c4878aSAndroid Build Coastguard Worker // Listen for connections on the given port.
307*61c4878aSAndroid Build Coastguard Worker // If port is 0, a random unused port is chosen and can be retrieved with
308*61c4878aSAndroid Build Coastguard Worker // port().
Listen(uint16_t port)309*61c4878aSAndroid Build Coastguard Worker Status ServerSocket::Listen(uint16_t port) {
310*61c4878aSAndroid Build Coastguard Worker int socket_fd = socket(AF_INET6, SOCK_STREAM, 0);
311*61c4878aSAndroid Build Coastguard Worker if (socket_fd == kInvalidFd) {
312*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
313*61c4878aSAndroid Build Coastguard Worker }
314*61c4878aSAndroid Build Coastguard Worker
315*61c4878aSAndroid Build Coastguard Worker // Allow binding to an address that may still be in use by a closed socket.
316*61c4878aSAndroid Build Coastguard Worker constexpr int value = 1;
317*61c4878aSAndroid Build Coastguard Worker setsockopt(socket_fd,
318*61c4878aSAndroid Build Coastguard Worker SOL_SOCKET,
319*61c4878aSAndroid Build Coastguard Worker SO_REUSEADDR,
320*61c4878aSAndroid Build Coastguard Worker reinterpret_cast<const char*>(&value),
321*61c4878aSAndroid Build Coastguard Worker sizeof(int));
322*61c4878aSAndroid Build Coastguard Worker
323*61c4878aSAndroid Build Coastguard Worker if (port != 0) {
324*61c4878aSAndroid Build Coastguard Worker struct sockaddr_in6 addr = {};
325*61c4878aSAndroid Build Coastguard Worker socklen_t addr_len = sizeof(addr);
326*61c4878aSAndroid Build Coastguard Worker addr.sin6_family = AF_INET6;
327*61c4878aSAndroid Build Coastguard Worker addr.sin6_port = htons(port);
328*61c4878aSAndroid Build Coastguard Worker addr.sin6_addr = in6addr_any;
329*61c4878aSAndroid Build Coastguard Worker if (bind(socket_fd, reinterpret_cast<sockaddr*>(&addr), addr_len) < 0) {
330*61c4878aSAndroid Build Coastguard Worker close(socket_fd);
331*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
332*61c4878aSAndroid Build Coastguard Worker }
333*61c4878aSAndroid Build Coastguard Worker }
334*61c4878aSAndroid Build Coastguard Worker
335*61c4878aSAndroid Build Coastguard Worker if (listen(socket_fd, kServerBacklogLength) < 0) {
336*61c4878aSAndroid Build Coastguard Worker close(socket_fd);
337*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
338*61c4878aSAndroid Build Coastguard Worker }
339*61c4878aSAndroid Build Coastguard Worker
340*61c4878aSAndroid Build Coastguard Worker // Find out which port the socket is listening on, and fill in port_.
341*61c4878aSAndroid Build Coastguard Worker struct sockaddr_in6 addr = {};
342*61c4878aSAndroid Build Coastguard Worker socklen_t addr_len = sizeof(addr);
343*61c4878aSAndroid Build Coastguard Worker if (getsockname(socket_fd, reinterpret_cast<sockaddr*>(&addr), &addr_len) <
344*61c4878aSAndroid Build Coastguard Worker 0 ||
345*61c4878aSAndroid Build Coastguard Worker static_cast<size_t>(addr_len) > sizeof(addr)) {
346*61c4878aSAndroid Build Coastguard Worker close(socket_fd);
347*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
348*61c4878aSAndroid Build Coastguard Worker }
349*61c4878aSAndroid Build Coastguard Worker
350*61c4878aSAndroid Build Coastguard Worker port_ = ntohs(addr.sin6_port);
351*61c4878aSAndroid Build Coastguard Worker
352*61c4878aSAndroid Build Coastguard Worker // Mark as ready and take ownership of the socket by this object.
353*61c4878aSAndroid Build Coastguard Worker {
354*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(socket_mutex_);
355*61c4878aSAndroid Build Coastguard Worker socket_fd_ = socket_fd;
356*61c4878aSAndroid Build Coastguard Worker TakeSocketWithLockHeld();
357*61c4878aSAndroid Build Coastguard Worker ready_ = true;
358*61c4878aSAndroid Build Coastguard Worker }
359*61c4878aSAndroid Build Coastguard Worker
360*61c4878aSAndroid Build Coastguard Worker return OkStatus();
361*61c4878aSAndroid Build Coastguard Worker }
362*61c4878aSAndroid Build Coastguard Worker
363*61c4878aSAndroid Build Coastguard Worker // Accept a connection. Blocks until after a client is connected.
364*61c4878aSAndroid Build Coastguard Worker // On success, returns a SocketStream connected to the new client.
Accept()365*61c4878aSAndroid Build Coastguard Worker Result<SocketStream> ServerSocket::Accept() {
366*61c4878aSAndroid Build Coastguard Worker struct sockaddr_in6 sockaddr_client_ = {};
367*61c4878aSAndroid Build Coastguard Worker socklen_t len = sizeof(sockaddr_client_);
368*61c4878aSAndroid Build Coastguard Worker
369*61c4878aSAndroid Build Coastguard Worker SocketOwnership ownership(this);
370*61c4878aSAndroid Build Coastguard Worker if (ownership.fd() == kInvalidFd) {
371*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
372*61c4878aSAndroid Build Coastguard Worker }
373*61c4878aSAndroid Build Coastguard Worker
374*61c4878aSAndroid Build Coastguard Worker // Wait for a connection or a tear down notification.
375*61c4878aSAndroid Build Coastguard Worker pollfd fds_to_poll[2];
376*61c4878aSAndroid Build Coastguard Worker fds_to_poll[0].fd = ownership.fd();
377*61c4878aSAndroid Build Coastguard Worker fds_to_poll[0].events = POLLIN | POLLERR | POLLHUP;
378*61c4878aSAndroid Build Coastguard Worker fds_to_poll[1].fd = ownership.pipe_r_fd();
379*61c4878aSAndroid Build Coastguard Worker fds_to_poll[1].events = POLLIN;
380*61c4878aSAndroid Build Coastguard Worker int rv = poll(fds_to_poll, 2, -1);
381*61c4878aSAndroid Build Coastguard Worker if ((rv <= 0) || !(fds_to_poll[0].revents & POLLIN)) {
382*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
383*61c4878aSAndroid Build Coastguard Worker }
384*61c4878aSAndroid Build Coastguard Worker
385*61c4878aSAndroid Build Coastguard Worker int connection_fd = accept(
386*61c4878aSAndroid Build Coastguard Worker ownership.fd(), reinterpret_cast<sockaddr*>(&sockaddr_client_), &len);
387*61c4878aSAndroid Build Coastguard Worker if (connection_fd == kInvalidFd) {
388*61c4878aSAndroid Build Coastguard Worker return Status::Unknown();
389*61c4878aSAndroid Build Coastguard Worker }
390*61c4878aSAndroid Build Coastguard Worker ConfigureSocket(connection_fd);
391*61c4878aSAndroid Build Coastguard Worker
392*61c4878aSAndroid Build Coastguard Worker return SocketStream(connection_fd);
393*61c4878aSAndroid Build Coastguard Worker }
394*61c4878aSAndroid Build Coastguard Worker
395*61c4878aSAndroid Build Coastguard Worker // Close the server socket, preventing further connections.
Close()396*61c4878aSAndroid Build Coastguard Worker void ServerSocket::Close() {
397*61c4878aSAndroid Build Coastguard Worker SocketOwnership ownership(this);
398*61c4878aSAndroid Build Coastguard Worker {
399*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(socket_mutex_);
400*61c4878aSAndroid Build Coastguard Worker if (ready_) {
401*61c4878aSAndroid Build Coastguard Worker // Shutdown the socket and send tear down notification to unblock any
402*61c4878aSAndroid Build Coastguard Worker // waiters.
403*61c4878aSAndroid Build Coastguard Worker if (socket_fd_ != kInvalidFd) {
404*61c4878aSAndroid Build Coastguard Worker shutdown(socket_fd_, SHUT_RDWR);
405*61c4878aSAndroid Build Coastguard Worker }
406*61c4878aSAndroid Build Coastguard Worker if (socket_pipe_w_fd_ != kInvalidFd) {
407*61c4878aSAndroid Build Coastguard Worker write(socket_pipe_w_fd_, "T", 1);
408*61c4878aSAndroid Build Coastguard Worker }
409*61c4878aSAndroid Build Coastguard Worker
410*61c4878aSAndroid Build Coastguard Worker // Release ownership of the socket by this object and mark as no longer
411*61c4878aSAndroid Build Coastguard Worker // ready.
412*61c4878aSAndroid Build Coastguard Worker ReleaseSocketWithLockHeld();
413*61c4878aSAndroid Build Coastguard Worker ready_ = false;
414*61c4878aSAndroid Build Coastguard Worker }
415*61c4878aSAndroid Build Coastguard Worker }
416*61c4878aSAndroid Build Coastguard Worker }
417*61c4878aSAndroid Build Coastguard Worker
TakeSocket()418*61c4878aSAndroid Build Coastguard Worker int ServerSocket::TakeSocket() {
419*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(socket_mutex_);
420*61c4878aSAndroid Build Coastguard Worker return TakeSocketWithLockHeld();
421*61c4878aSAndroid Build Coastguard Worker }
422*61c4878aSAndroid Build Coastguard Worker
TakeSocketWithLockHeld()423*61c4878aSAndroid Build Coastguard Worker int ServerSocket::TakeSocketWithLockHeld() {
424*61c4878aSAndroid Build Coastguard Worker ++socket_own_count_;
425*61c4878aSAndroid Build Coastguard Worker
426*61c4878aSAndroid Build Coastguard Worker if (ready_ && (socket_fd_ != kInvalidFd) &&
427*61c4878aSAndroid Build Coastguard Worker (socket_pipe_r_fd_ == kInvalidFd)) {
428*61c4878aSAndroid Build Coastguard Worker int fd_list[2];
429*61c4878aSAndroid Build Coastguard Worker if (pipe(fd_list) >= 0) {
430*61c4878aSAndroid Build Coastguard Worker socket_pipe_r_fd_ = fd_list[0];
431*61c4878aSAndroid Build Coastguard Worker socket_pipe_w_fd_ = fd_list[1];
432*61c4878aSAndroid Build Coastguard Worker }
433*61c4878aSAndroid Build Coastguard Worker }
434*61c4878aSAndroid Build Coastguard Worker
435*61c4878aSAndroid Build Coastguard Worker if (!ready_ || (socket_pipe_r_fd_ == kInvalidFd) ||
436*61c4878aSAndroid Build Coastguard Worker (socket_pipe_w_fd_ == kInvalidFd)) {
437*61c4878aSAndroid Build Coastguard Worker return kInvalidFd;
438*61c4878aSAndroid Build Coastguard Worker }
439*61c4878aSAndroid Build Coastguard Worker return socket_fd_;
440*61c4878aSAndroid Build Coastguard Worker }
441*61c4878aSAndroid Build Coastguard Worker
ReleaseSocket()442*61c4878aSAndroid Build Coastguard Worker void ServerSocket::ReleaseSocket() {
443*61c4878aSAndroid Build Coastguard Worker std::lock_guard lock(socket_mutex_);
444*61c4878aSAndroid Build Coastguard Worker ReleaseSocketWithLockHeld();
445*61c4878aSAndroid Build Coastguard Worker }
446*61c4878aSAndroid Build Coastguard Worker
ReleaseSocketWithLockHeld()447*61c4878aSAndroid Build Coastguard Worker void ServerSocket::ReleaseSocketWithLockHeld() {
448*61c4878aSAndroid Build Coastguard Worker --socket_own_count_;
449*61c4878aSAndroid Build Coastguard Worker
450*61c4878aSAndroid Build Coastguard Worker if (socket_own_count_ <= 0) {
451*61c4878aSAndroid Build Coastguard Worker ready_ = false;
452*61c4878aSAndroid Build Coastguard Worker if (socket_fd_ != kInvalidFd) {
453*61c4878aSAndroid Build Coastguard Worker close(socket_fd_);
454*61c4878aSAndroid Build Coastguard Worker socket_fd_ = kInvalidFd;
455*61c4878aSAndroid Build Coastguard Worker }
456*61c4878aSAndroid Build Coastguard Worker if (socket_pipe_r_fd_ != kInvalidFd) {
457*61c4878aSAndroid Build Coastguard Worker close(socket_pipe_r_fd_);
458*61c4878aSAndroid Build Coastguard Worker socket_pipe_r_fd_ = kInvalidFd;
459*61c4878aSAndroid Build Coastguard Worker }
460*61c4878aSAndroid Build Coastguard Worker if (socket_pipe_w_fd_ != kInvalidFd) {
461*61c4878aSAndroid Build Coastguard Worker close(socket_pipe_w_fd_);
462*61c4878aSAndroid Build Coastguard Worker socket_pipe_w_fd_ = kInvalidFd;
463*61c4878aSAndroid Build Coastguard Worker }
464*61c4878aSAndroid Build Coastguard Worker }
465*61c4878aSAndroid Build Coastguard Worker }
466*61c4878aSAndroid Build Coastguard Worker
467*61c4878aSAndroid Build Coastguard Worker } // namespace pw::stream
468