OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "tools/android/forwarder2/socket.h" | |
6 | |
7 #include <arpa/inet.h> | |
8 #include <fcntl.h> | |
9 #include <netdb.h> | |
10 #include <netinet/in.h> | |
11 #include <stdio.h> | |
12 #include <string.h> | |
13 #include <sys/socket.h> | |
14 #include <sys/types.h> | |
15 | |
16 #include "base/eintr_wrapper.h" | |
17 #include "base/logging.h" | |
18 #include "base/safe_strerror_posix.h" | |
19 #include "tools/android/common/net.h" | |
20 | |
21 #define PRESERVE_ERRNO_HANDLE_EINTR(Func) \ | |
Satish
2012/09/06 15:53:12
is preserving the errno important? i.e. are we wri
felipeg
2012/09/06 16:19:06
I currently don't, but Digit told me that it would
Satish
2012/09/07 09:11:38
I'd prefer we don't add code expecting in future s
felipeg
2012/09/07 13:19:26
Done.
digit
2012/09/07 13:47:12
Preserving errno for Close() is important because
felipeg
2012/09/07 13:56:57
Done.
| |
22 do { \ | |
23 int local_errno = errno; \ | |
24 (void) HANDLE_EINTR(Func); \ | |
25 errno = local_errno; \ | |
26 } while (false); | |
27 | |
28 namespace forwarder { | |
29 | |
30 bool Socket::BindUnix(const string& path, bool abstract) { | |
31 errno = 0; | |
32 if (!InitUnixSocket(path, abstract) || !BindAndListen()) { | |
33 Close(); | |
34 return false; | |
35 } | |
36 return true; | |
37 } | |
38 | |
39 bool Socket::BindTcp(const string& host, int port) { | |
40 errno = 0; | |
41 if (!InitTcpSocket(host, port) || !BindAndListen()) { | |
42 Close(); | |
43 return false; | |
44 } | |
45 return true; | |
46 } | |
47 | |
48 bool Socket::ConnectUnix(const string& path, bool abstract) { | |
49 errno = 0; | |
50 if (!InitUnixSocket(path, abstract) || !Connect()) { | |
51 Close(); | |
52 return false; | |
53 } | |
54 return true; | |
55 } | |
56 | |
57 bool Socket::ConnectTcp(const string& host, int port) { | |
58 errno = 0; | |
59 if (!InitTcpSocket(host, port) || !Connect()) { | |
60 Close(); | |
61 return false; | |
62 } | |
63 return true; | |
64 } | |
65 | |
66 Socket::Socket() | |
67 : socket_(-1), | |
68 port_(0), | |
69 socket_error_(false), | |
70 family_(AF_INET), | |
71 abstract_(false), | |
72 addr_ptr_(reinterpret_cast<sockaddr*>(&addr_.addr4)), | |
73 addr_len_(sizeof(sockaddr)), | |
74 exit_notifier_fd_(-1) { | |
75 memset(&addr_, 0, sizeof(addr_)); | |
76 } | |
77 | |
78 Socket::~Socket() { | |
79 CHECK(IsClosed()); | |
80 } | |
81 | |
82 void Socket::Shutdown() { | |
83 if (!IsClosed()) { | |
84 // Preserving the errno in case we are trying to shutdown a socket that | |
85 // already had an error. | |
86 PRESERVE_ERRNO_HANDLE_EINTR(shutdown(socket_, SHUT_RDWR)); | |
87 } | |
88 } | |
89 | |
90 void Socket::Close() { | |
91 if (!IsClosed()) { | |
92 PRESERVE_ERRNO_HANDLE_EINTR(close(socket_)); | |
93 socket_ = -1; | |
94 } | |
95 } | |
96 | |
97 bool Socket::InitSocketInternal() { | |
98 socket_ = socket(family_, SOCK_STREAM, 0); | |
99 if (socket_ < 0) | |
100 return false; | |
101 tools::DisableNagle(socket_); | |
102 int reuse_addr = 1; | |
103 setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, | |
104 &reuse_addr, sizeof(reuse_addr)); | |
105 tools::DeferAccept(socket_); | |
106 return true; | |
107 } | |
108 | |
109 bool Socket::InitUnixSocket(const string& path, bool abstract) { | |
110 static const size_t kPathMax = sizeof(addr_.addr_un.sun_path); | |
111 if (abstract + path.size() + 1 /* '\0' */ > kPathMax) { | |
Satish
2012/09/06 15:53:12
I don't understand the reason to add the boolean w
Philippe
2012/09/06 16:00:11
It's not obvious indeed. When using the abstract n
felipeg
2012/09/06 16:19:06
FYI, this check also came from net/base/unix_domai
digit
2012/09/07 13:47:12
I'd suggest adding a comment here explaining this
felipeg
2012/09/07 13:56:57
Done.
| |
112 LOG(ERROR) << "The provided path is too big to create a unix " | |
113 << "domain socket: " << path; | |
114 return false; | |
115 } | |
116 abstract_ = abstract; | |
117 family_ = PF_UNIX; | |
118 addr_.addr_un.sun_family = family_; | |
119 | |
120 if (abstract) { | |
121 // Copied from net/base/unix_domain_socket_posix.cc | |
122 // Convert the path given into abstract socket name. It must start with | |
123 // the '\0' character, so we are adding it. |addr_len| must specify the | |
124 // length of the structure exactly, as potentially the socket name may | |
125 // have '\0' characters embedded (although we don't support this). | |
126 // Note that addr_.addr_un.sun_path is already zero initialized. | |
127 memcpy(addr_.addr_un.sun_path + 1, path.c_str(), path.size()); | |
128 addr_len_ = path.size() + offsetof(struct sockaddr_un, sun_path) + 1; | |
129 } else { | |
130 memcpy(addr_.addr_un.sun_path, path.c_str(), path.size()); | |
131 addr_len_ = sizeof(sockaddr_un); | |
132 } | |
133 | |
134 addr_ptr_ = reinterpret_cast<sockaddr*>(&addr_.addr_un); | |
135 return InitSocketInternal(); | |
136 } | |
137 | |
138 bool Socket::InitTcpSocket(const string& host, int port) { | |
139 port_ = port; | |
140 | |
141 if (host.empty()) { | |
142 // Use localhost: INADDR_LOOPBACK | |
143 family_ = AF_INET; | |
144 addr_.addr4.sin_family = family_; | |
145 addr_.addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
146 } else if (!Resolve(host)) { | |
147 return false; | |
148 } | |
149 CHECK(family_ == AF_INET || family_ == AF_INET6) | |
150 << "Error initializing socket."; | |
Satish
2012/09/06 15:53:12
the message should be about the failure, so could
felipeg
2012/09/06 16:19:06
Done.
| |
151 if (family_ == AF_INET) { | |
152 addr_.addr4.sin_port = htons(port_); | |
153 addr_ptr_ = reinterpret_cast<sockaddr*>(&addr_.addr4); | |
154 addr_len_ = sizeof(sockaddr_in); | |
Satish
2012/09/06 15:53:12
would be better to use sizeof(addr_.addr4) since t
felipeg
2012/09/06 16:19:06
Done.
| |
155 } else if (family_ == AF_INET6) { | |
156 addr_.addr6.sin6_port = htons(port_); | |
157 addr_ptr_ = reinterpret_cast<sockaddr*>(&addr_.addr6); | |
158 addr_len_ = sizeof(sockaddr_in6); | |
159 } | |
160 return InitSocketInternal(); | |
161 } | |
162 | |
163 bool Socket::BindAndListen() { | |
164 errno = 0; | |
165 if (HANDLE_EINTR(bind(socket_, addr_ptr_, addr_len_)) < 0 || | |
166 HANDLE_EINTR(listen(socket_, 5)) < 0) { | |
167 SetSocketError(); | |
168 return false; | |
169 } | |
170 return true; | |
171 } | |
172 | |
173 bool Socket::Accept(Socket* new_socket) { | |
174 DCHECK(new_socket != NULL); | |
175 if (!WaitForEvent()) { | |
176 SetSocketError(); | |
177 return false; | |
178 } | |
179 errno = 0; | |
180 int new_socket_fd = HANDLE_EINTR(accept(socket_, NULL, NULL)); | |
181 if (new_socket_fd < 0) { | |
182 SetSocketError(); | |
183 return false; | |
184 } | |
185 | |
186 tools::DisableNagle(new_socket_fd); | |
187 new_socket->socket_ = new_socket_fd; | |
188 return true; | |
189 } | |
190 | |
191 bool Socket::Connect() { | |
192 errno = 0; | |
193 if (HANDLE_EINTR(connect(socket_, addr_ptr_, addr_len_)) < 0) { | |
194 SetSocketError(); | |
195 return false; | |
196 } | |
197 return true; | |
198 } | |
199 | |
200 bool Socket::Resolve(const string& host) { | |
201 struct addrinfo hints; | |
202 struct addrinfo* res; | |
203 memset(&hints, 0, sizeof(hints)); | |
204 hints.ai_family = PF_UNSPEC; | |
205 hints.ai_socktype = SOCK_STREAM; | |
206 hints.ai_flags |= AI_CANONNAME; | |
207 | |
208 int errcode = getaddrinfo(host.c_str(), NULL, &hints, &res); | |
209 if (errcode != 0) { | |
210 SetSocketError(); | |
211 return false; | |
212 } | |
213 family_ = res->ai_family; | |
214 switch (res->ai_family) { | |
215 case AF_INET: | |
216 memcpy(&addr_.addr4, | |
217 reinterpret_cast<sockaddr_in*>(res->ai_addr), | |
218 sizeof(sockaddr_in)); | |
219 break; | |
220 case AF_INET6: | |
221 memcpy(&addr_.addr6, | |
222 reinterpret_cast<sockaddr_in6*>(res->ai_addr), | |
223 sizeof(sockaddr_in6)); | |
224 break; | |
225 } | |
226 return true; | |
227 } | |
228 | |
229 bool Socket::IsFdInSet(const fd_set& fds) const { | |
230 if (IsClosed()) | |
231 return false; | |
232 return FD_ISSET(socket_, &fds); | |
233 } | |
234 | |
235 bool Socket::AddFdToSet(fd_set* fds) const { | |
236 if (IsClosed()) | |
237 return false; | |
238 FD_SET(socket_, fds); | |
239 return true; | |
240 } | |
241 | |
242 int Socket::ReadNumBytes(char* buffer, size_t num_bytes) { | |
243 int bytes_read = 0; | |
244 int ret = 1; | |
245 while (bytes_read < num_bytes && ret > 0) { | |
246 ret = Read(buffer + bytes_read, num_bytes - bytes_read); | |
247 if (ret >= 0) | |
248 bytes_read += ret; | |
249 } | |
250 return bytes_read; | |
251 } | |
252 | |
253 void Socket::SetSocketError() { | |
254 socket_error_ = true; | |
255 // We never use non-blocking socket. | |
256 DCHECK(errno != EAGAIN && errno != EWOULDBLOCK); | |
257 Close(); | |
258 } | |
259 | |
260 int Socket::Read(char* buffer, size_t buffer_size) { | |
261 if (!WaitForEvent()) { | |
262 SetSocketError(); | |
263 return 0; | |
264 } | |
265 int ret = HANDLE_EINTR(read(socket_, buffer, buffer_size)); | |
266 if (ret < 0) | |
267 SetSocketError(); | |
268 return ret; | |
269 } | |
270 | |
271 int Socket::Write(const char* buffer, size_t count) { | |
272 int ret = HANDLE_EINTR(send(socket_, buffer, count, MSG_NOSIGNAL)); | |
273 if (ret < 0) | |
274 SetSocketError(); | |
275 return ret; | |
276 } | |
277 | |
278 int Socket::WriteNumBytes(const char* buffer, size_t num_bytes) { | |
279 int bytes_written = 0; | |
280 int ret = 1; | |
281 while (bytes_written < num_bytes && ret > 0) { | |
282 ret = Write(buffer + bytes_written, num_bytes - bytes_written); | |
283 if (ret >= 0) | |
284 bytes_written += ret; | |
285 } | |
286 return bytes_written; | |
287 } | |
288 | |
289 bool Socket::WaitForEvent() const { | |
290 if (exit_notifier_fd_ == -1 || socket_ == -1) | |
291 return true; | |
292 const int nfds = std::max(socket_, exit_notifier_fd_) + 1; | |
293 fd_set read_fds; | |
294 FD_ZERO(&read_fds); | |
295 FD_SET(socket_, &read_fds); | |
296 FD_SET(exit_notifier_fd_, &read_fds); | |
297 if (HANDLE_EINTR(select(nfds, &read_fds, NULL, NULL, NULL)) <= 0) | |
298 return false; | |
299 return !FD_ISSET(exit_notifier_fd_, &read_fds); | |
300 } | |
301 | |
302 // static | |
303 int Socket::GetHighestFileDescriptor( | |
304 const Socket& s1, const Socket& s2) { | |
305 return std::max(s1.socket_, s2.socket_); | |
306 } | |
307 | |
308 } // namespace forwarder | |
OLD | NEW |