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

Side by Side Diff: content/browser/renderer_host/p2p_socket_host_posix.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_socket_host_posix.h"
6
7 #include <errno.h>
8 #include <net/if.h>
9 #include <netinet/in.h>
10 #include <sys/ioctl.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <sys/utsname.h>
14 #include <unistd.h>
15
16 #include "content/browser/renderer_host/p2p_sockets_host.h"
17 #include "content/common/p2p_messages.h"
18 #include "net/base/net_util.h"
19
20 namespace {
21
22 // This method returns address of the first IPv4 enabled network
23 // interface it finds ignoring the loopback interface. This address is
24 // used for all sockets.
25 //
26 // TODO(sergeyu): This approach works only in the simplest case when
27 // host has only one network connection. Instead of binding all
28 // connections to this interface we must provide list of interfaces to
29 // the renderer, and let the PortAllocater in the renderer process
30 // choose local address.
31 bool GetLocalAddress(sockaddr_in* addr) {
32 int fd;
33 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
34 LOG(ERROR) << "socket() failed: " << fd;
35 return false;
36 }
37
38 struct ifconf ifc;
39 ifc.ifc_len = 64 * sizeof(struct ifreq);
40 scoped_array<char> ifc_buffer(new char[ifc.ifc_len]);
41 ifc.ifc_buf = ifc_buffer.get();
42
43 int result = ioctl(fd, SIOCGIFCONF, &ifc);
44 if (result < 0) {
45 LOG(ERROR) << "GetLocalAddress: ioctl returned error:" << result;
46 close(fd);
47 return false;
48 }
49 CHECK_LT(ifc.ifc_len, static_cast<int>(64 * sizeof(struct ifreq)));
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 close(fd);
70
71 return found;
72 }
73
74 bool SocketAddressToSockAddr(P2PSocketAddress address, sockaddr_in* addr) {
75 // TODO(sergeyu): Add IPv6 support.
76 if (address.address.size() != 4) {
77 return false;
78 }
79
80 addr->sin_family = AF_INET;
81 memcpy(&addr->sin_addr, &address.address[0], 4);
82 addr->sin_port = htons(address.port);
83 return true;
84 }
85
86 bool SockAddrToSocketAddress(sockaddr_in* addr,
87 P2PSocketAddress* address) {
88 if (addr->sin_family != AF_INET) {
89 LOG(ERROR) << "SockAddrToSocketAddress: only IPv4 addresses are supported";
90 // TODO(sergeyu): Add IPv6 support.
91 return false;
92 }
93
94 address->address.resize(4);
95 memcpy(&address->address[0], &addr->sin_addr, 4);
96 address->port = ntohs(addr->sin_port);
97
98 return true;
99 }
100
101 } // namespace
102
103 P2PSocketHostPosix::P2PSocketHostPosix(
104 P2PSocketsHost* host, int routing_id, int id)
105 : P2PSocketHost(host, routing_id, id),
106 state_(STATE_UNINITIALIZED), socket_(0), read_watcher_(this) {
107 }
108
109 P2PSocketHostPosix::~P2PSocketHostPosix() {
110 if (state_ == STATE_OPEN) {
111 DCHECK_NE(socket_, 0);
112 close(socket_);
113 }
114 }
115
116 bool P2PSocketHostPosix::Init() {
117 socket_ = socket(AF_INET, SOCK_DGRAM, 0);
118 if (socket_ < 0) {
119 LOG(ERROR) << "Failed to create socket: " << socket_;
120 OnError();
121 return false;
122 }
123
124 int result = net::SetNonBlocking(socket_);
125 if (result < 0) {
126 LOG(ERROR) << "Failed to set O_NONBLOCK flag: " << result;
127 OnError();
128 return false;
129 }
130
131 sockaddr_in addr;
132 if (!GetLocalAddress(&addr)) {
133 LOG(ERROR) << "Failed to get local network address.";
134 OnError();
135 return false;
136 }
137
138 result = bind(socket_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
139 if (result < 0) {
140 LOG(ERROR) << "bind() failed: " << result;
141 OnError();
142 return false;
143 }
144
145 if (!MessageLoopForIO::current()->WatchFileDescriptor(
146 socket_, true, MessageLoopForIO::WATCH_READ,
147 &read_socket_watcher_, &read_watcher_)) {
148 LOG(ERROR) << "WatchFileDescriptor failed on read, errno: " << errno;
149 OnError();
150 return false;
151 }
152
153 socklen_t addrlen = sizeof(addr);
154 result = getsockname(socket_, reinterpret_cast<sockaddr*>(&addr),
155 &addrlen);
156 if (result < 0) {
157 LOG(ERROR) << "P2PSocket::Init(): unable to get local addr: "
158 << result;
159 OnError();
160 return false;
161 }
162
163 P2PSocketAddress address;
164 if (!SockAddrToSocketAddress(&addr, &address)) {
165 OnError();
166 return false;
167 }
168
169 VLOG(1) << "getsockname() returned "
170 << net::NetAddressToString(
171 reinterpret_cast<sockaddr*>(&addr), sizeof(addr))
172 << ":" << address.port;
173
174 state_ = STATE_OPEN;
175
176 host_->Send(new P2PMsg_OnSocketCreated(routing_id_, id_, address));
177
178 return true;
179 }
180
181 void P2PSocketHostPosix::OnError() {
182 if (socket_ != 0) {
183 close(socket_);
184 socket_ = 0;
185 }
186
187 if (state_ == STATE_UNINITIALIZED || state_ == STATE_OPEN) {
188 host_->Send(new P2PMsg_OnError(routing_id_, id_));
189 }
190
191 state_ = STATE_ERROR;
192 }
193
194 void P2PSocketHostPosix::DidCompleteRead() {
195 if (state_ != STATE_OPEN) {
196 return;
197 }
198
199 std::vector<char> data;
200 data.resize(4096);
201 sockaddr_in addr;
202 socklen_t addr_len = sizeof(addr);
203 int result = recvfrom(socket_, &data[0], data.size(), 0,
204 reinterpret_cast<sockaddr*>(&addr), &addr_len);
205 if (result > 0) {
206 data.resize(result);
207 VLOG(2) << "received " << result << " bytes from "
208 << net::NetAddressToString(
209 reinterpret_cast<sockaddr*>(&addr), sizeof(addr))
210 << ":" << ntohs(addr.sin_port);
211 P2PSocketAddress address;
212 if (!SockAddrToSocketAddress(&addr, &address)) {
213 // Address conversion fails only if we receive a non-IPv4
214 // packet, which should never happen because the socket is IPv4.
215 NOTREACHED();
216 return;
217 }
218
219 host_->Send(new P2PMsg_OnDataReceived(routing_id_, id_,
220 address, data));
221 } else if (result < 0) {
222 LOG(ERROR) << "recvfrom() returned error: " << result;
223 OnError();
224 }
225 }
226
227 void P2PSocketHostPosix::Send(P2PSocketAddress socket_address,
228 const std::vector<char>& data) {
229 sockaddr_in addr;
230 SocketAddressToSockAddr(socket_address, &addr);
231 int result = sendto(socket_, &data[0], data.size(), 0,
232 reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
233 if (result < 0) {
234 LOG(ERROR) << "Send failed.";
235 } else {
236 VLOG(2) << "Sent " << result << " bytes to "
237 << net::NetAddressToString(
238 reinterpret_cast<sockaddr*>(&addr), sizeof(addr))
239 << ":" << ntohs(addr.sin_port);
240 }
241 }
242
243 // static
244 P2PSocketHost* P2PSocketHost::Create(
245 P2PSocketsHost* host, int routing_id, int id, P2PSocketType type) {
246 switch (type) {
247 case P2P_SOCKET_UDP:
248 return new P2PSocketHostPosix(host, routing_id, id);
249
250 case P2P_SOCKET_TCP_SERVER:
251 // TODO(sergeyu): Implement TCP sockets support.
252 return NULL;
253
254 case P2P_SOCKET_TCP_CLIENT:
255 return NULL;
256 }
257
258 NOTREACHED();
259 return NULL;
260 }
OLDNEW
« no previous file with comments | « content/browser/renderer_host/p2p_socket_host_posix.h ('k') | content/browser/renderer_host/p2p_socket_host_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698