Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(236)

Side by Side Diff: tools/android/forwarder2/socket.cc

Issue 10916112: Forwarder 2 implementation (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/android/forwarder2/socket.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 // This is used in Close and Shutdown.
22 // Preserving errno for Close() is important because the function is very often
23 // used in cleanup code, after an error occurred, and it is very easy to pass an
24 // invalid file descriptor to close() in this context, or more rarely, a
25 // spurious signal might make close() return -1 + setting errno to EINTR,
26 // masking the real reason for the original error. This leads to very unpleasant
27 // debugging sessions.
28 #define PRESERVE_ERRNO_HANDLE_EINTR(Func) \
29 do { \
30 int local_errno = errno; \
31 (void) HANDLE_EINTR(Func); \
32 errno = local_errno; \
33 } while (false);
34
35
36 namespace forwarder2 {
37
38 bool Socket::BindUnix(const std::string& path, bool abstract) {
39 errno = 0;
40 if (!InitUnixSocket(path, abstract) || !BindAndListen()) {
41 Close();
42 return false;
43 }
44 return true;
45 }
46
47 bool Socket::BindTcp(const std::string& host, int port) {
48 errno = 0;
49 if (!InitTcpSocket(host, port) || !BindAndListen()) {
50 Close();
51 return false;
52 }
53 return true;
54 }
55
56 bool Socket::ConnectUnix(const std::string& path, bool abstract) {
57 errno = 0;
58 if (!InitUnixSocket(path, abstract) || !Connect()) {
59 Close();
60 return false;
61 }
62 return true;
63 }
64
65 bool Socket::ConnectTcp(const std::string& host, int port) {
66 errno = 0;
67 if (!InitTcpSocket(host, port) || !Connect()) {
68 Close();
69 return false;
70 }
71 return true;
72 }
73
74 Socket::Socket()
75 : socket_(-1),
76 port_(0),
77 socket_error_(false),
78 family_(AF_INET),
79 abstract_(false),
80 addr_ptr_(reinterpret_cast<sockaddr*>(&addr_.addr4)),
81 addr_len_(sizeof(sockaddr)),
82 exit_notifier_fd_(-1) {
83 memset(&addr_, 0, sizeof(addr_));
84 }
85
86 Socket::~Socket() {
87 CHECK(IsClosed());
88 }
89
90 void Socket::Shutdown() {
91 if (!IsClosed()) {
92 PRESERVE_ERRNO_HANDLE_EINTR(shutdown(socket_, SHUT_RDWR));
93 }
94 }
95
96 void Socket::Close() {
97 if (!IsClosed()) {
98 PRESERVE_ERRNO_HANDLE_EINTR(close(socket_));
99 socket_ = -1;
100 }
101 }
102
103 bool Socket::InitSocketInternal() {
104 socket_ = socket(family_, SOCK_STREAM, 0);
105 if (socket_ < 0)
106 return false;
107 tools::DisableNagle(socket_);
108 int reuse_addr = 1;
109 setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
110 &reuse_addr, sizeof(reuse_addr));
111 tools::DeferAccept(socket_);
112 return true;
113 }
114
115 bool Socket::InitUnixSocket(const std::string& path, bool abstract) {
116 static const size_t kPathMax = sizeof(addr_.addr_un.sun_path);
117 // For abstract sockets we need one extra byte for the leading zero.
118 if (abstract && path.size() + 2 /* '\0' */ > kPathMax ||
119 !abstract && path.size() + 1 /* '\0' */ > kPathMax) {
120 LOG(ERROR) << "The provided path is too big to create a unix "
121 << "domain socket: " << path;
122 return false;
123 }
124 abstract_ = abstract;
125 family_ = PF_UNIX;
126 addr_.addr_un.sun_family = family_;
127
128 if (abstract) {
129 // Copied from net/base/unix_domain_socket_posix.cc
130 // Convert the path given into abstract socket name. It must start with
131 // the '\0' character, so we are adding it. |addr_len| must specify the
132 // length of the structure exactly, as potentially the socket name may
133 // have '\0' characters embedded (although we don't support this).
134 // Note that addr_.addr_un.sun_path is already zero initialized.
135 memcpy(addr_.addr_un.sun_path + 1, path.c_str(), path.size());
136 addr_len_ = path.size() + offsetof(struct sockaddr_un, sun_path) + 1;
137 } else {
138 memcpy(addr_.addr_un.sun_path, path.c_str(), path.size());
139 addr_len_ = sizeof(sockaddr_un);
140 }
141
142 addr_ptr_ = reinterpret_cast<sockaddr*>(&addr_.addr_un);
143 return InitSocketInternal();
144 }
145
146 bool Socket::InitTcpSocket(const std::string& host, int port) {
147 port_ = port;
148
149 if (host.empty()) {
150 // Use localhost: INADDR_LOOPBACK
151 family_ = AF_INET;
152 addr_.addr4.sin_family = family_;
153 addr_.addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
154 } else if (!Resolve(host)) {
155 return false;
156 }
157 CHECK(family_ == AF_INET || family_ == AF_INET6)
158 << "Invalid socket family.";
159 if (family_ == AF_INET) {
160 addr_.addr4.sin_port = htons(port_);
161 addr_ptr_ = reinterpret_cast<sockaddr*>(&addr_.addr4);
162 addr_len_ = sizeof(addr_.addr4);
163 } else if (family_ == AF_INET6) {
164 addr_.addr6.sin6_port = htons(port_);
165 addr_ptr_ = reinterpret_cast<sockaddr*>(&addr_.addr6);
166 addr_len_ = sizeof(addr_.addr6);
167 }
168 return InitSocketInternal();
169 }
170
171 bool Socket::BindAndListen() {
172 errno = 0;
173 if (HANDLE_EINTR(bind(socket_, addr_ptr_, addr_len_)) < 0 ||
174 HANDLE_EINTR(listen(socket_, 5)) < 0) {
175 SetSocketError();
176 return false;
177 }
178 return true;
179 }
180
181 bool Socket::Accept(Socket* new_socket) {
182 DCHECK(new_socket != NULL);
183 if (!WaitForEvent()) {
184 SetSocketError();
185 return false;
186 }
187 errno = 0;
188 int new_socket_fd = HANDLE_EINTR(accept(socket_, NULL, NULL));
189 if (new_socket_fd < 0) {
190 SetSocketError();
191 return false;
192 }
193
194 tools::DisableNagle(new_socket_fd);
195 new_socket->socket_ = new_socket_fd;
196 return true;
197 }
198
199 bool Socket::Connect() {
200 errno = 0;
201 if (HANDLE_EINTR(connect(socket_, addr_ptr_, addr_len_)) < 0) {
202 SetSocketError();
203 return false;
204 }
205 return true;
206 }
207
208 bool Socket::Resolve(const std::string& host) {
209 struct addrinfo hints;
210 struct addrinfo* res;
211 memset(&hints, 0, sizeof(hints));
212 hints.ai_family = AF_UNSPEC;
213 hints.ai_socktype = SOCK_STREAM;
214 hints.ai_flags |= AI_CANONNAME;
215
216 int errcode = getaddrinfo(host.c_str(), NULL, &hints, &res);
217 if (errcode != 0) {
218 SetSocketError();
219 return false;
220 }
221 family_ = res->ai_family;
222 switch (res->ai_family) {
223 case AF_INET:
224 memcpy(&addr_.addr4,
225 reinterpret_cast<sockaddr_in*>(res->ai_addr),
226 sizeof(sockaddr_in));
227 break;
228 case AF_INET6:
229 memcpy(&addr_.addr6,
230 reinterpret_cast<sockaddr_in6*>(res->ai_addr),
231 sizeof(sockaddr_in6));
232 break;
233 }
234 return true;
235 }
236
237 bool Socket::IsFdInSet(const fd_set& fds) const {
238 if (IsClosed())
239 return false;
240 return FD_ISSET(socket_, &fds);
241 }
242
243 bool Socket::AddFdToSet(fd_set* fds) const {
244 if (IsClosed())
245 return false;
246 FD_SET(socket_, fds);
247 return true;
248 }
249
250 int Socket::ReadNumBytes(char* buffer, size_t num_bytes) {
251 int bytes_read = 0;
252 int ret = 1;
253 while (bytes_read < num_bytes && ret > 0) {
254 ret = Read(buffer + bytes_read, num_bytes - bytes_read);
255 if (ret >= 0)
256 bytes_read += ret;
257 }
258 return bytes_read;
259 }
260
261 void Socket::SetSocketError() {
262 socket_error_ = true;
263 // We never use non-blocking socket.
264 DCHECK(errno != EAGAIN && errno != EWOULDBLOCK);
265 Close();
266 }
267
268 int Socket::Read(char* buffer, size_t buffer_size) {
269 if (!WaitForEvent()) {
270 SetSocketError();
271 return 0;
272 }
273 int ret = HANDLE_EINTR(read(socket_, buffer, buffer_size));
274 if (ret < 0)
275 SetSocketError();
276 return ret;
277 }
278
279 int Socket::Write(const char* buffer, size_t count) {
280 int ret = HANDLE_EINTR(send(socket_, buffer, count, MSG_NOSIGNAL));
281 if (ret < 0)
282 SetSocketError();
283 return ret;
284 }
285
286 int Socket::WriteString(const std::string& buffer) {
287 return WriteNumBytes(buffer.c_str(), buffer.size());
288 }
289
290 int Socket::WriteNumBytes(const char* buffer, size_t num_bytes) {
291 int bytes_written = 0;
292 int ret = 1;
293 while (bytes_written < num_bytes && ret > 0) {
294 ret = Write(buffer + bytes_written, num_bytes - bytes_written);
295 if (ret >= 0)
296 bytes_written += ret;
297 }
298 return bytes_written;
299 }
300
301 bool Socket::WaitForEvent() const {
302 if (exit_notifier_fd_ == -1 || socket_ == -1)
303 return true;
304 const int nfds = std::max(socket_, exit_notifier_fd_) + 1;
305 fd_set read_fds;
306 FD_ZERO(&read_fds);
307 FD_SET(socket_, &read_fds);
308 FD_SET(exit_notifier_fd_, &read_fds);
309 if (HANDLE_EINTR(select(nfds, &read_fds, NULL, NULL, NULL)) <= 0)
310 return false;
311 return !FD_ISSET(exit_notifier_fd_, &read_fds);
312 }
313
314 // static
315 int Socket::GetHighestFileDescriptor(
316 const Socket& s1, const Socket& s2) {
317 return std::max(s1.socket_, s2.socket_);
318 }
319
320 } // namespace forwarder
OLDNEW
« no previous file with comments | « tools/android/forwarder2/socket.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698