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) : fd_(fd), am_(am), watching_(false) {
42 int flags = fcntl(fd, F_GETFL);
43 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
44
45 flags = fcntl(fd, F_GETFD);
46 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
47
48 #ifdef SO_NOSIGPIPE
49 // Disable SIGPIPE generation on Darwin.
50 // When writing to a broken pipe, send() will return -1 and
51 // set errno to EPIPE.
52 flags = 1;
53 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&flags, sizeof(flags));
54 #endif
55 }
56
PosixAsyncSocket(PosixAsyncSocket && other)57 PosixAsyncSocket::PosixAsyncSocket(PosixAsyncSocket&& other) {
58 fd_ = other.fd_;
59 watching_ = other.watching_.load();
60 am_ = other.am_;
61
62 other.fd_ = -1;
63 other.watching_ = false;
64 }
~PosixAsyncSocket()65 PosixAsyncSocket::~PosixAsyncSocket() { Close(); }
66
Recv(uint8_t * buffer,uint64_t bufferSize)67 ssize_t PosixAsyncSocket::Recv(uint8_t* buffer, uint64_t bufferSize) {
68 if (fd_ == -1) {
69 // Socket was closed locally.
70 return 0;
71 }
72
73 errno = 0;
74 ssize_t res = 0;
75 REPEAT_UNTIL_NO_INTR(res = read(fd_, buffer, bufferSize));
76
77 if (res < 0) {
78 DD("Recv < 0: {} ({})", strerror(errno), fd_);
79 }
80 DD("{} bytes ({})", res, fd_);
81 return res;
82 }
83
Send(const uint8_t * buffer,uint64_t bufferSize)84 ssize_t PosixAsyncSocket::Send(const uint8_t* buffer, uint64_t bufferSize) {
85 errno = 0;
86 ssize_t res = 0;
87 #ifdef MSG_NOSIGNAL
88 // Prevent SIGPIPE generation on Linux when writing to a broken pipe.
89 // ::send() will return -1/EPIPE instead.
90 const int sendFlags = MSG_NOSIGNAL;
91 #else
92 // For Darwin, this is handled by setting SO_NOSIGPIPE when creating
93 // the socket.
94 const int sendFlags = 0;
95 #endif
96
97 REPEAT_UNTIL_NO_INTR(res = send(fd_, buffer, bufferSize, sendFlags));
98
99 DD("{} bytes ({})", res, fd_);
100 return res;
101 }
102
Connected()103 bool PosixAsyncSocket::Connected() {
104 if (fd_ == -1) {
105 return false;
106 }
107 char buf;
108 if (recv(fd_, &buf, 1, MSG_PEEK | MSG_DONTWAIT) != 1) {
109 DD("Recv not 1, could be connected: {} ({})", strerror(errno), fd_);
110 return errno == EAGAIN || errno == EWOULDBLOCK;
111 }
112
113 // We saw a byte in the queue, we are likely connected.
114 return true;
115 }
116
Close()117 void PosixAsyncSocket::Close() {
118 if (fd_ == -1) {
119 return;
120 }
121
122 StopWatching();
123
124 // Clear out error
125 int error_code = 0;
126 socklen_t error_code_size = sizeof(error_code);
127 getsockopt(fd_, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&error_code), &error_code_size);
128
129 // shutdown sockets if possible,
130 REPEAT_UNTIL_NO_INTR(shutdown(fd_, SHUT_RDWR));
131
132 error_code = ::close(fd_);
133 if (error_code == -1) {
134 INFO("Failed to close: {} ({})", strerror(errno), fd_);
135 }
136 INFO("({})", fd_);
137 fd_ = -1;
138 }
139
WatchForNonBlockingRead(const ReadCallback & on_read_ready_callback)140 bool PosixAsyncSocket::WatchForNonBlockingRead(const ReadCallback& on_read_ready_callback) {
141 bool expected = false;
142 if (watching_.compare_exchange_strong(expected, true)) {
143 return am_->WatchFdForNonBlockingReads(fd_, [on_read_ready_callback, this](int /* fd */) {
144 on_read_ready_callback(this);
145 }) == 0;
146 }
147 return false;
148 }
149
StopWatching()150 void PosixAsyncSocket::StopWatching() {
151 bool expected = true;
152 if (watching_.compare_exchange_strong(expected, false)) {
153 am_->StopWatchingFileDescriptor(fd_);
154 }
155 }
156 } // namespace net
157 } // namespace android
158