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

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

Powered by Google App Engine
This is Rietveld 408576698