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

Side by Side Diff: content/browser/renderer_host/p2p_sockets_host.cc

Issue 6598053: P2P Sockets host implementation. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: - Created 9 years, 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "content/browser/renderer_host/p2p_sockets_host.h"
6
7 #include "chrome/common/render_messages.h"
8 #include "net/base/net_util.h"
9
10 // Currently P2P Sockets are not implemented for Windows yet.
11 // TODO(sergeyu) implement P2PSocket on Windows.
12 #if !defined(OS_WIN)
13
14 #include <errno.h>
15 #include <net/if.h>
16 #include <netinet/in.h>
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 #include <sys/utsname.h>
21 #include <unistd.h>
22
23 namespace {
24
25 // This method returns address of the first IPv4 enabled network
26 // interface it finds ignoring the loopback interface. This address is
27 // used for all sockets.
28 //
29 // TODO(sergeyu): This approach works only in the simplest case when
30 // host has only one network connection. Instead of binding all
31 // connections to this interface we must provide list of interfaces to
32 // the renderer, and let the PortAllocater in the renderer process
33 // choose local address.
34 bool GetLocalAddress(sockaddr_in* addr) {
35 int fd;
36 if ((fd = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
37 LOG(ERROR) << "socket() failed: " << fd;
38 return false;
39 }
40
41 struct ifconf ifc;
42 ifc.ifc_len = 64 * sizeof(struct ifreq);
43 scoped_array<char> ifc_buffer(new char[ifc.ifc_len]);
44 ifc.ifc_buf = ifc_buffer.get();
45
46 int result = ::ioctl(fd, SIOCGIFCONF, &ifc);
47 if (result < 0) {
48 LOG(ERROR) << "GetLocalAddress: ioctl returned error:" << result;
49 ::close(fd);
awong 2011/03/01 19:57:53 Do we need to explicilty specify the global scope
Sergey Ulanov 2011/03/01 22:34:17 No we don't need it, I just though it looks better
50 return false;
51 }
52 CHECK_LT(ifc.ifc_len, static_cast<int>(64 * sizeof(struct ifreq)));
53
54 struct ifreq* ptr = reinterpret_cast<struct ifreq*>(ifc.ifc_buf);
55 struct ifreq* end =
56 reinterpret_cast<struct ifreq*>(ifc.ifc_buf + ifc.ifc_len);
57
58 bool found = false;
59 while (ptr < end) {
60 struct sockaddr_in* inaddr =
61 reinterpret_cast<struct sockaddr_in*>(&ptr->ifr_ifru.ifru_addr);
62 if (inaddr->sin_family == AF_INET &&
63 strncmp(ptr->ifr_name, "lo", 2) != 0) {
64 memcpy(addr, inaddr, sizeof(sockaddr_in));
65 found = true;
66 break;
67 }
68
69 ptr++;
70 }
71
72 ::close(fd);
73
74 return found;
75 }
76
77 bool SocketAddressToSockAddr(P2PSocketAddress address, sockaddr_in* addr) {
78 // TODO(sergeyu): Add IPv6 support.
79 if (address.address.size() != 4) {
80 return false;
81 }
82
83 addr->sin_family = AF_INET;
84 memcpy(&addr->sin_addr, &address.address[0], 4);
85 addr->sin_port = htons(address.port);
86 return true;
87 }
88
89 bool SockAddrToSocketAddress(sockaddr_in* addr,
90 P2PSocketAddress* address) {
91 if (addr->sin_family != AF_INET) {
92 LOG(ERROR) << "SockAddrToSocketAddress: only IPv4 addresses are supported";
93 // TODO(sergeyu): Add IPv6 support.
94 return false;
95 }
96
97 address->address.resize(4);
98 memcpy(&address->address[0], &addr->sin_addr, 4);
99 address->port = ntohs(addr->sin_port);
100
101 return true;
102 }
103
104 } // namespace
105
106 class P2PSocketsHost::P2PSocket {
jam 2011/03/01 19:35:54 i'm curious, why isn't this class defined in a sep
Sergey Ulanov 2011/03/01 22:34:17 Done.
107 public:
108 P2PSocket(P2PSocketsHost* host, int routing_id, int id);
109 ~P2PSocket();
110
111 bool Init();
112
113 void Send(P2PSocketAddress socket_address, const std::vector<char>& data);
114 void DestroyConnection(P2PSocketAddress socket_address);
115
116 private:
117 enum State {
118 STATE_UNINITIALIZED,
119 STATE_OPEN,
120 STATE_ERROR,
121 };
122
123 class ReadWatcher : public MessageLoopForIO::Watcher {
124 public:
125 explicit ReadWatcher(P2PSocketsHost::P2PSocket* socket) : socket_(socket) {}
126
127 // MessageLoopForIO::Watcher methods
128 virtual void OnFileCanReadWithoutBlocking(int /* fd */) {
129 socket_->DidCompleteRead();
130 }
131 virtual void OnFileCanWriteWithoutBlocking(int /* fd */) {}
132
133 private:
134 P2PSocketsHost::P2PSocket* socket_;
135
136 DISALLOW_COPY_AND_ASSIGN(ReadWatcher);
137 };
138
139 void DidCompleteRead();
140 void OnError();
141
142 P2PSocketsHost* host_;
143 int routing_id_;
144 int id_;
145 State state_;
146 int socket_;
147 MessageLoopForIO::FileDescriptorWatcher read_socket_watcher_;
148 ReadWatcher read_watcher_;
149
150 DISALLOW_COPY_AND_ASSIGN(P2PSocket);
151 };
152
153 P2PSocketsHost::P2PSocket::P2PSocket(
154 P2PSocketsHost* host, int routing_id, int id)
155 : host_(host), routing_id_(routing_id), id_(id),
156 state_(STATE_UNINITIALIZED), socket_(0), read_watcher_(this) {
157 }
158
159 P2PSocketsHost::P2PSocket::~P2PSocket() {
160 if (state_ == STATE_OPEN) {
161 DCHECK_NE(socket_, 0);
162 ::close(socket_);
163 }
164 }
165
166 bool P2PSocketsHost::P2PSocket::Init() {
167 socket_ = socket(AF_INET, SOCK_DGRAM, 0);
168 if (socket_ < 0) {
169 LOG(ERROR) << "Failed to create socket: " << socket_;
170 OnError();
171 return false;
172 }
173
174 int result = net::SetNonBlocking(socket_);
175 if (result < 0) {
176 LOG(ERROR) << "Failed to set O_NONBLOCK flag: " << result;
177 OnError();
178 return false;
179 }
180
181 sockaddr_in addr;
182 if (!GetLocalAddress(&addr)) {
183 LOG(ERROR) << "Failed to get local network address.";
184 OnError();
185 return false;
186 }
187
188 result = ::bind(socket_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
189 if (result < 0) {
190 LOG(ERROR) << "bind() failed: " << result;
191 OnError();
192 return false;
193 }
194
195 if (!MessageLoopForIO::current()->WatchFileDescriptor(
196 socket_, true, MessageLoopForIO::WATCH_READ,
197 &read_socket_watcher_, &read_watcher_)) {
198 LOG(ERROR) << "WatchFileDescriptor failed on read, errno: " << errno;
199 OnError();
200 return false;
201 }
202
203 socklen_t addrlen = sizeof(addr);
204 result = ::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr),
205 &addrlen);
206 if (result < 0) {
207 LOG(ERROR) << "P2PSocket::Init(): unable to get local addr: "
208 << result;
209 OnError();
210 return false;
211 }
212
213 P2PSocketAddress address;
214 if (!SockAddrToSocketAddress(&addr, &address)) {
215 OnError();
216 return false;
217 }
218
219 VLOG(1) << "getsockname() returned "
220 << net::NetAddressToString(
221 reinterpret_cast<sockaddr*>(&addr), sizeof(addr))
222 << ":" << address.port;
223
224 state_ = STATE_OPEN;
225
226 host_->Send(new ViewMsg_P2P_OnSocketCreated(routing_id_, id_, address));
227
228 return true;
229 }
230
231 void P2PSocketsHost::P2PSocket::OnError() {
232 if (socket_ != 0) {
233 ::close(socket_);
234 socket_ = 0;
235 }
236
237 if (state_ == STATE_UNINITIALIZED || state_ == STATE_OPEN) {
238 host_->Send(new ViewMsg_P2P_OnError(routing_id_, id_));
239 }
240
241 state_ = STATE_ERROR;
242 }
243
244 void P2PSocketsHost::P2PSocket::DidCompleteRead() {
245 if (state_ != STATE_OPEN) {
246 return;
247 }
248
249 std::vector<char> data;
250 data.resize(4096);
251 sockaddr_in addr;
252 socklen_t addr_len = sizeof(addr);
253 int result = ::recvfrom(socket_, &data[0], data.size(), 0,
254 reinterpret_cast<sockaddr*>(&addr), &addr_len);
255 if (result > 0) {
256 data.resize(result);
257 VLOG(2) << "received " << result << " bytes from "
258 << net::NetAddressToString(
259 reinterpret_cast<sockaddr*>(&addr), sizeof(addr))
260 << ":" << ntohs(addr.sin_port);
261 P2PSocketAddress address;
262 if (!SockAddrToSocketAddress(&addr, &address)) {
263 // Address conversion fails only if we receive a non-IPv4
264 // packet, which should never happen because the socket is IPv4.
265 NOTREACHED();
266 return;
267 }
268
269 host_->Send(new ViewMsg_P2P_OnDataReceived(routing_id_, id_,
270 address, data));
271 } else if (result < 0) {
272 LOG(ERROR) << "recvfrom() returned error: " << result;
273 OnError();
274 }
275 }
276
277 void P2PSocketsHost::P2PSocket::Send(P2PSocketAddress socket_address,
278 const std::vector<char>& data) {
279 sockaddr_in addr;
280 SocketAddressToSockAddr(socket_address, &addr);
281 int result = sendto(socket_, &data[0], data.size(), 0,
282 reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
283 if (result < 0) {
284 LOG(ERROR) << "Send failed.";
285 } else {
286 VLOG(2) << "Sent " << result << " bytes to "
287 << net::NetAddressToString(
288 reinterpret_cast<sockaddr*>(&addr), sizeof(addr))
289 << ":" << ntohs(addr.sin_port);
290 }
291 }
292
293 #else // defined(OS_WIN)
294
295 class P2PSocketsHost::P2PSocket {
296 public:
297 P2PSocket(P2PSocketsHost* host, int routing_id, int id)
298 : host_(host), routing_id_(routing_id), id_(id) {
299 }
300 ~P2PSocket() { }
301
302 bool Init() {
303 host_->Send(new ViewMsg_P2P_OnError(routing_id_, id_));
304 return false;
305 }
306
307 void Send(P2PSocketAddress socket_address, const std::vector<char>& data) { }
308 void DestroyConnection(P2PSocketAddress socket_address) { }
309
310 private:
311 P2PSocketsHost* host_;
312 int routing_id_;
313 int id_;
314
315 DISALLOW_COPY_AND_ASSIGN(P2PSocket);
316 };
317
318 #endif // defined(OS_WIN)
319
320 P2PSocketsHost::P2PSocketsHost() {
321 }
322
323 P2PSocketsHost::~P2PSocketsHost() {
324 }
325
326 void P2PSocketsHost::OnChannelClosing() {
327 BrowserMessageFilter::OnChannelClosing();
328
329 // Since the IPC channel is gone, close pending connections.
330 for (IDMap<P2PSocket>::iterator i(&sockets_); !i.IsAtEnd(); i.Advance()) {
331 sockets_.Remove(i.GetCurrentKey());
332 }
333 }
334
335 void P2PSocketsHost::OnDestruct() const {
336 BrowserThread::DeleteOnIOThread::Destruct(this);
337 }
338
339 bool P2PSocketsHost::OnMessageReceived(const IPC::Message& message,
340 bool* message_was_ok) {
jam 2011/03/01 19:35:54 nit: spacing
Sergey Ulanov 2011/03/01 22:34:17 Done.
341 bool handled = true;
342 IPC_BEGIN_MESSAGE_MAP_EX(P2PSocketsHost, message, *message_was_ok)
343 IPC_MESSAGE_HANDLER(ViewHostMsg_P2P_CreateSocket, OnCreateSocket)
344 IPC_MESSAGE_HANDLER(ViewHostMsg_P2P_Send, OnSend)
345 IPC_MESSAGE_HANDLER(ViewHostMsg_P2P_DestroySocket, OnDestroySocket)
346 IPC_MESSAGE_UNHANDLED(handled = false)
347 IPC_END_MESSAGE_MAP_EX()
348 return handled;
349 }
350
351 void P2PSocketsHost::OnCreateSocket(
352 const IPC::Message& msg, P2PSocketType type, int socket_id,
353 P2PSocketAddress remote_address) {
354 if (sockets_.Lookup(socket_id)) {
355 LOG(ERROR) << "Received ViewHostMsg_P2P_CreateSocket for socket "
356 "that already exists.";
357 return;
358 }
359
360 if (type != P2P_SOCKET_UDP) {
361 Send(new ViewMsg_P2P_OnError(msg.routing_id(), socket_id));
362 return;
363 }
364
365 scoped_ptr<P2PSocket> socket(
366 new P2PSocket(this, msg.routing_id(), socket_id));
367 if (socket->Init()) {
368 sockets_.AddWithID(socket.release(), socket_id);
369 }
370 }
371
372 void P2PSocketsHost::OnSend(const IPC::Message& msg, int socket_id,
373 P2PSocketAddress socket_address,
jam 2011/03/01 19:35:54 nit: spacing
Sergey Ulanov 2011/03/01 22:34:17 Done.
374 const std::vector<char>& data) {
375 P2PSocket* socket = sockets_.Lookup(socket_id);
376 if (!socket) {
377 LOG(ERROR) << "Received ViewHostMsg_P2P_Send for invalid socket_id.";
378 return;
379 }
380 socket->Send(socket_address, data);
381 }
382
383 void P2PSocketsHost::OnDestroySocket(const IPC::Message& msg, int socket_id) {
384 sockets_.Remove(socket_id);
385 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698