OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/p2p/ipc_socket_factory.h" | 5 #include "content/renderer/p2p/ipc_socket_factory.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/message_loop_proxy.h" | 9 #include "base/message_loop_proxy.h" |
10 #include "content/renderer/p2p/socket_client.h" | 10 #include "content/renderer/p2p/socket_client.h" |
11 #include "content/renderer/p2p/socket_dispatcher.h" | 11 #include "content/renderer/p2p/socket_dispatcher.h" |
12 #include "jingle/glue/utils.h" | 12 #include "jingle/glue/utils.h" |
13 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" | 13 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" |
14 | 14 |
15 namespace content { | 15 namespace content { |
16 | 16 |
17 namespace { | 17 namespace { |
18 | 18 |
19 // TODO(sergeyu): Try adjusting these parameters to achieve optimal performance. | |
20 const int kMaxPendingPackets = 8; | |
21 const int kWritableSignalThreshold = 0; | |
22 | |
19 // IpcPacketSocket implements talk_base::AsyncPacketSocket interface | 23 // IpcPacketSocket implements talk_base::AsyncPacketSocket interface |
20 // using P2PSocketClient that works over IPC-channel. It must be used | 24 // using P2PSocketClient that works over IPC-channel. It must be used |
21 // on the thread it was created. | 25 // on the thread it was created. |
22 class IpcPacketSocket : public talk_base::AsyncPacketSocket, | 26 class IpcPacketSocket : public talk_base::AsyncPacketSocket, |
23 public P2PSocketClient::Delegate { | 27 public P2PSocketClient::Delegate { |
24 public: | 28 public: |
25 IpcPacketSocket(); | 29 IpcPacketSocket(); |
26 virtual ~IpcPacketSocket(); | 30 virtual ~IpcPacketSocket(); |
27 | 31 |
28 // Always takes ownership of client even if initialization fails. | 32 // Always takes ownership of client even if initialization fails. |
(...skipping 11 matching lines...) Expand all Loading... | |
40 virtual State GetState() const OVERRIDE; | 44 virtual State GetState() const OVERRIDE; |
41 virtual int GetOption(talk_base::Socket::Option opt, int* value) OVERRIDE; | 45 virtual int GetOption(talk_base::Socket::Option opt, int* value) OVERRIDE; |
42 virtual int SetOption(talk_base::Socket::Option opt, int value) OVERRIDE; | 46 virtual int SetOption(talk_base::Socket::Option opt, int value) OVERRIDE; |
43 virtual int GetError() const OVERRIDE; | 47 virtual int GetError() const OVERRIDE; |
44 virtual void SetError(int error) OVERRIDE; | 48 virtual void SetError(int error) OVERRIDE; |
45 | 49 |
46 // P2PSocketClient::Delegate implementation. | 50 // P2PSocketClient::Delegate implementation. |
47 virtual void OnOpen(const net::IPEndPoint& address) OVERRIDE; | 51 virtual void OnOpen(const net::IPEndPoint& address) OVERRIDE; |
48 virtual void OnIncomingTcpConnection(const net::IPEndPoint& address, | 52 virtual void OnIncomingTcpConnection(const net::IPEndPoint& address, |
49 P2PSocketClient* client) OVERRIDE; | 53 P2PSocketClient* client) OVERRIDE; |
54 virtual void OnSendComplete() OVERRIDE; | |
50 virtual void OnError() OVERRIDE; | 55 virtual void OnError() OVERRIDE; |
51 virtual void OnDataReceived(const net::IPEndPoint& address, | 56 virtual void OnDataReceived(const net::IPEndPoint& address, |
52 const std::vector<char>& data) OVERRIDE; | 57 const std::vector<char>& data) OVERRIDE; |
53 | 58 |
54 private: | 59 private: |
55 enum InternalState { | 60 enum InternalState { |
56 IS_UNINITIALIZED, | 61 IS_UNINITIALIZED, |
57 IS_OPENING, | 62 IS_OPENING, |
58 IS_OPEN, | 63 IS_OPEN, |
59 IS_CLOSED, | 64 IS_CLOSED, |
(...skipping 16 matching lines...) Expand all Loading... | |
76 // renderer side doesn't know the address until it receives OnOpen() | 81 // renderer side doesn't know the address until it receives OnOpen() |
77 // event from the browser. | 82 // event from the browser. |
78 talk_base::SocketAddress local_address_; | 83 talk_base::SocketAddress local_address_; |
79 | 84 |
80 // Remote address for client TCP connections. | 85 // Remote address for client TCP connections. |
81 talk_base::SocketAddress remote_address_; | 86 talk_base::SocketAddress remote_address_; |
82 | 87 |
83 // Current state of the object. | 88 // Current state of the object. |
84 InternalState state_; | 89 InternalState state_; |
85 | 90 |
91 // Number which have been sent to the browser, but for which we haven't | |
92 // received response. | |
93 int send_packets_pending_; | |
94 | |
95 // Set to true once EWOULDBLOCK was returned from Send(). Indicates that the | |
96 // caller expects SignalWritable notification. | |
97 bool writable_signal_expected_; | |
98 | |
86 // Current error code. Valid when state_ == IS_ERROR. | 99 // Current error code. Valid when state_ == IS_ERROR. |
87 int error_; | 100 int error_; |
88 | 101 |
89 DISALLOW_COPY_AND_ASSIGN(IpcPacketSocket); | 102 DISALLOW_COPY_AND_ASSIGN(IpcPacketSocket); |
90 }; | 103 }; |
91 | 104 |
92 IpcPacketSocket::IpcPacketSocket() | 105 IpcPacketSocket::IpcPacketSocket() |
93 : type_(P2P_SOCKET_UDP), | 106 : type_(P2P_SOCKET_UDP), |
94 message_loop_(MessageLoop::current()), | 107 message_loop_(MessageLoop::current()), |
95 state_(IS_UNINITIALIZED), | 108 state_(IS_UNINITIALIZED), |
109 send_packets_pending_(0), | |
110 writable_signal_expected_(false), | |
96 error_(0) { | 111 error_(0) { |
97 } | 112 } |
98 | 113 |
99 IpcPacketSocket::~IpcPacketSocket() { | 114 IpcPacketSocket::~IpcPacketSocket() { |
100 if (state_ == IS_OPENING || state_ == IS_OPEN || | 115 if (state_ == IS_OPENING || state_ == IS_OPEN || |
101 state_ == IS_ERROR) { | 116 state_ == IS_ERROR) { |
102 Close(); | 117 Close(); |
103 } | 118 } |
104 } | 119 } |
105 | 120 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 return EWOULDBLOCK; | 188 return EWOULDBLOCK; |
174 case IS_CLOSED: | 189 case IS_CLOSED: |
175 return ENOTCONN; | 190 return ENOTCONN; |
176 case IS_ERROR: | 191 case IS_ERROR: |
177 return error_; | 192 return error_; |
178 case IS_OPEN: | 193 case IS_OPEN: |
179 // Continue sending the packet. | 194 // Continue sending the packet. |
180 break; | 195 break; |
181 } | 196 } |
182 | 197 |
198 if (send_packets_pending_ > kMaxPendingPackets) { | |
199 writable_signal_expected_ = true; | |
200 return EWOULDBLOCK; | |
Ronghua Wu (Left Chromium)
2013/04/04 23:53:02
Justin, you mentioned in my cl that you want somet
Ronghua Wu (Left Chromium)
2013/04/05 17:56:04
Should we set error_ to EWOULDBLOCK? IOW, should t
Sergey Ulanov
2013/04/05 21:04:03
That's a good point. I think we should return -1 h
| |
201 } | |
202 | |
183 const char* data_char = reinterpret_cast<const char*>(data); | 203 const char* data_char = reinterpret_cast<const char*>(data); |
184 std::vector<char> data_vector(data_char, data_char + data_size); | 204 std::vector<char> data_vector(data_char, data_char + data_size); |
185 | 205 |
186 net::IPEndPoint address_chrome; | 206 net::IPEndPoint address_chrome; |
187 if (!jingle_glue::SocketAddressToIPEndPoint(address, &address_chrome)) { | 207 if (!jingle_glue::SocketAddressToIPEndPoint(address, &address_chrome)) { |
188 // Just drop the packet if we failed to convert the address. | 208 // Just drop the packet if we failed to convert the address. |
189 return 0; | 209 return 0; |
190 } | 210 } |
191 | 211 |
212 ++send_packets_pending_; | |
192 client_->Send(address_chrome, data_vector); | 213 client_->Send(address_chrome, data_vector); |
193 | 214 |
194 // Fake successful send. The caller ignores result anyway. | 215 // Fake successful send. The caller ignores result anyway. |
195 return data_size; | 216 return data_size; |
196 } | 217 } |
197 | 218 |
198 int IpcPacketSocket::Close() { | 219 int IpcPacketSocket::Close() { |
199 DCHECK_EQ(MessageLoop::current(), message_loop_); | 220 DCHECK_EQ(MessageLoop::current(), message_loop_); |
200 | 221 |
201 client_->Close(); | 222 client_->Close(); |
(...skipping 29 matching lines...) Expand all Loading... | |
231 return STATE_CLOSED; | 252 return STATE_CLOSED; |
232 } | 253 } |
233 | 254 |
234 int IpcPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) { | 255 int IpcPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) { |
235 // We don't support socket options for IPC sockets. | 256 // We don't support socket options for IPC sockets. |
236 return -1; | 257 return -1; |
237 } | 258 } |
238 | 259 |
239 int IpcPacketSocket::SetOption(talk_base::Socket::Option opt, int value) { | 260 int IpcPacketSocket::SetOption(talk_base::Socket::Option opt, int value) { |
240 // We don't support socket options for IPC sockets. | 261 // We don't support socket options for IPC sockets. |
241 // | |
242 // TODO(sergeyu): Make sure we set proper socket options on the | |
243 // browser side. | |
244 return -1; | 262 return -1; |
245 } | 263 } |
246 | 264 |
247 int IpcPacketSocket::GetError() const { | 265 int IpcPacketSocket::GetError() const { |
248 DCHECK_EQ(MessageLoop::current(), message_loop_); | 266 DCHECK_EQ(MessageLoop::current(), message_loop_); |
249 return error_; | 267 return error_; |
250 } | 268 } |
251 | 269 |
252 void IpcPacketSocket::SetError(int error) { | 270 void IpcPacketSocket::SetError(int error) { |
253 DCHECK_EQ(MessageLoop::current(), message_loop_); | 271 DCHECK_EQ(MessageLoop::current(), message_loop_); |
(...skipping 26 matching lines...) Expand all Loading... | |
280 | 298 |
281 talk_base::SocketAddress remote_address; | 299 talk_base::SocketAddress remote_address; |
282 if (!jingle_glue::IPEndPointToSocketAddress(address, &remote_address)) { | 300 if (!jingle_glue::IPEndPointToSocketAddress(address, &remote_address)) { |
283 // Always expect correct IPv4 address to be allocated. | 301 // Always expect correct IPv4 address to be allocated. |
284 NOTREACHED(); | 302 NOTREACHED(); |
285 } | 303 } |
286 socket->InitAcceptedTcp(client, local_address_, remote_address); | 304 socket->InitAcceptedTcp(client, local_address_, remote_address); |
287 SignalNewConnection(this, socket.release()); | 305 SignalNewConnection(this, socket.release()); |
288 } | 306 } |
289 | 307 |
308 void IpcPacketSocket::OnSendComplete() { | |
309 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
310 | |
311 --send_packets_pending_; | |
312 DCHECK_GE(send_packets_pending_, 0); | |
313 | |
314 if (writable_signal_expected_ && | |
315 send_packets_pending_ <= kWritableSignalThreshold) { | |
316 // TODO(sergeyu): Uncomment this line once SignalWritable is added in | |
317 // talk_base::AsyncPacketSocket. | |
318 // | |
319 // SignalWritable(this); | |
320 writable_signal_expected_ = false; | |
321 } | |
322 } | |
323 | |
290 void IpcPacketSocket::OnError() { | 324 void IpcPacketSocket::OnError() { |
291 DCHECK_EQ(MessageLoop::current(), message_loop_); | 325 DCHECK_EQ(MessageLoop::current(), message_loop_); |
292 state_ = IS_ERROR; | 326 state_ = IS_ERROR; |
293 error_ = ECONNABORTED; | 327 error_ = ECONNABORTED; |
294 } | 328 } |
295 | 329 |
296 void IpcPacketSocket::OnDataReceived(const net::IPEndPoint& address, | 330 void IpcPacketSocket::OnDataReceived(const net::IPEndPoint& address, |
297 const std::vector<char>& data) { | 331 const std::vector<char>& data) { |
298 DCHECK_EQ(MessageLoop::current(), message_loop_); | 332 DCHECK_EQ(MessageLoop::current(), message_loop_); |
299 | 333 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
361 talk_base::SocketAddress crome_address; | 395 talk_base::SocketAddress crome_address; |
362 P2PSocketClient* socket_client = new P2PSocketClient(socket_dispatcher_); | 396 P2PSocketClient* socket_client = new P2PSocketClient(socket_dispatcher_); |
363 scoped_ptr<IpcPacketSocket> socket(new IpcPacketSocket()); | 397 scoped_ptr<IpcPacketSocket> socket(new IpcPacketSocket()); |
364 if (!socket->Init(P2P_SOCKET_TCP_CLIENT, socket_client, local_address, | 398 if (!socket->Init(P2P_SOCKET_TCP_CLIENT, socket_client, local_address, |
365 remote_address)) | 399 remote_address)) |
366 return NULL; | 400 return NULL; |
367 return socket.release(); | 401 return socket.release(); |
368 } | 402 } |
369 | 403 |
370 } // namespace content | 404 } // namespace content |
OLD | NEW |