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

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

Powered by Google App Engine
This is Rietveld 408576698