1 // Copyright (C) 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "net/posix/posix_async_socket.h"
15
16 #include <errno.h> // for errno
17 #include <fcntl.h> // for fcntl, FD_CLOEXEC, F_GETFL
18 #include <string.h> // for strerror
19 #include <sys/socket.h> // for getsockopt, send, MSG_NOSIGNAL
20 #include <unistd.h> // for close, read
21
22 #include <functional> // for __base
23
24 #include "log.h"
25 #include "model/setup/async_manager.h" // for AsyncManager
26
27 #ifdef _WIN32
28 #include "msvc-posix.h"
29 #endif
30
31 /* set for very verbose debugging */
32 #ifdef NDEBUG
33 #define DD(...) (void)0
34 #else
35 #define DD(...) INFO(__VA_ARGS__)
36 #endif
37
38 namespace android {
39 namespace net {
40
PosixAsyncSocket(int fd,AsyncManager * am)41 PosixAsyncSocket::PosixAsyncSocket(int fd, AsyncManager* am)
42 : fd_(fd), am_(am), watching_(false) {
43 int flags = fcntl(fd, F_GETFL);
44 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
45
46 flags = fcntl(fd, F_GETFD);
47 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
48
49 #ifdef SO_NOSIGPIPE
50 // Disable SIGPIPE generation on Darwin.
51 // When writing to a broken pipe, send() will return -1 and
52 // set errno to EPIPE.
53 flags = 1;
54 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&flags, sizeof(flags));
55 #endif
56 }
57
PosixAsyncSocket(PosixAsyncSocket && other)58 PosixAsyncSocket::PosixAsyncSocket(PosixAsyncSocket&& other) {
59 fd_ = other.fd_;
60 watching_ = other.watching_.load();
61 am_ = other.am_;
62
63 other.fd_ = -1;
64 other.watching_ = false;
65 }
~PosixAsyncSocket()66 PosixAsyncSocket::~PosixAsyncSocket() { Close(); }
67
Recv(uint8_t * buffer,uint64_t bufferSize)68 ssize_t PosixAsyncSocket::Recv(uint8_t* buffer, uint64_t bufferSize) {
69 if (fd_ == -1) {
70 // Socket was closed locally.
71 return 0;
72 }
73
74 errno = 0;
75 ssize_t res = 0;
76 REPEAT_UNTIL_NO_INTR(res = read(fd_, buffer, bufferSize));
77
78 if (res < 0) {
79 DD("Recv < 0: {} ({})", strerror(errno), fd_);
80 }
81 DD("{} bytes ({})", res, fd_);
82 return res;
83 };
84
Send(const uint8_t * buffer,uint64_t bufferSize)85 ssize_t PosixAsyncSocket::Send(const uint8_t* buffer, uint64_t bufferSize) {
86 errno = 0;
87 ssize_t res = 0;
88 #ifdef MSG_NOSIGNAL
89 // Prevent SIGPIPE generation on Linux when writing to a broken pipe.
90 // ::send() will return -1/EPIPE instead.
91 const int sendFlags = MSG_NOSIGNAL;
92 #else
93 // For Darwin, this is handled by setting SO_NOSIGPIPE when creating
94 // the socket.
95 const int sendFlags = 0;
96 #endif
97
98 REPEAT_UNTIL_NO_INTR(res = send(fd_, buffer, bufferSize, sendFlags));
99
100 DD("{} bytes ({})", res, fd_);
101 return res;
102 }
103
Connected()104 bool PosixAsyncSocket::Connected() {
105 if (fd_ == -1) {
106 return false;
107 }
108 char buf;
109 if (recv(fd_, &buf, 1, MSG_PEEK | MSG_DONTWAIT) != 1) {
110 DD("Recv not 1, could be connected: {} ({})", strerror(errno), fd_);
111 return errno == EAGAIN || errno == EWOULDBLOCK;
112 }
113
114 // We saw a byte in the queue, we are likely connected.
115 return true;
116 }
117
Close()118 void PosixAsyncSocket::Close() {
119 if (fd_ == -1) {
120 return;
121 }
122
123 StopWatching();
124
125 // Clear out error
126 int error_code = 0;
127 socklen_t error_code_size = sizeof(error_code);
128 getsockopt(fd_, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&error_code),
129 &error_code_size);
130
131 // shutdown sockets if possible,
132 REPEAT_UNTIL_NO_INTR(shutdown(fd_, SHUT_RDWR));
133
134 error_code = ::close(fd_);
135 if (error_code == -1) {
136 INFO("Failed to close: {} ({})", strerror(errno), fd_);
137 }
138 INFO("({})", fd_);
139 fd_ = -1;
140 }
141
WatchForNonBlockingRead(const ReadCallback & on_read_ready_callback)142 bool PosixAsyncSocket::WatchForNonBlockingRead(
143 const ReadCallback& on_read_ready_callback) {
144 bool expected = false;
145 if (watching_.compare_exchange_strong(expected, true)) {
146 return am_->WatchFdForNonBlockingReads(
147 fd_, [on_read_ready_callback, this](int /* fd */) {
148 on_read_ready_callback(this);
149 }) == 0;
150 }
151 return false;
152 }
153
StopWatching()154 void PosixAsyncSocket::StopWatching() {
155 bool expected = true;
156 if (watching_.compare_exchange_strong(expected, false)) {
157 am_->StopWatchingFileDescriptor(fd_);
158 }
159 }
160 } // namespace net
161 } // namespace android
162