OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 "jingle/glue/pseudotcp_adapter.h" | 5 #include "jingle/glue/pseudotcp_adapter.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/time.h" | 8 #include "base/time.h" |
9 #include "net/base/address_list.h" | 9 #include "net/base/address_list.h" |
10 #include "net/base/completion_callback.h" | 10 #include "net/base/completion_callback.h" |
11 #include "net/base/io_buffer.h" | 11 #include "net/base/io_buffer.h" |
12 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
13 #include "net/base/net_util.h" | 13 #include "net/base/net_util.h" |
14 | 14 |
15 using cricket::PseudoTcp; | 15 using cricket::PseudoTcp; |
16 | 16 |
17 namespace { | 17 namespace { |
18 const int kReadBufferSize = 65536; // Maximum size of a packet. | 18 const int kReadBufferSize = 65536; // Maximum size of a packet. |
19 const uint16 kDefaultMtu = 1280; | 19 const uint16 kDefaultMtu = 1280; |
20 } // namespace | 20 } // namespace |
21 | 21 |
22 namespace jingle_glue { | 22 namespace jingle_glue { |
23 | 23 |
24 PseudoTcpAdapter::PseudoTcpAdapter(net::Socket* socket) | 24 class PseudoTcpAdapter::Core : public cricket::IPseudoTcpNotify, |
25 : socket_(socket), | 25 public base::RefCounted<Core> { |
26 ALLOW_THIS_IN_INITIALIZER_LIST(pseudotcp_(this, 0)), | 26 public: |
27 connect_callback_(NULL), | 27 Core(net::Socket* socket); |
28 virtual ~Core(); | |
29 | |
30 // Functions used to implement net::StreamSocket. | |
31 virtual int Read(net::IOBuffer* buffer, int buffer_size, | |
Sergey Ulanov
2011/05/20 22:01:40
Do these methods need to be virtual?
Wez
2011/05/21 08:10:55
Done.
| |
32 net::CompletionCallback* callback); | |
33 virtual int Write(net::IOBuffer* buffer, int buffer_size, | |
34 net::CompletionCallback* callback); | |
35 virtual int Connect(net::CompletionCallback* callback); | |
36 | |
37 // cricket::IPseudoTcpNotify interface. | |
38 // These notifications are triggered from NotifyPacket. | |
39 virtual void OnTcpOpen(cricket::PseudoTcp* tcp) OVERRIDE; | |
40 virtual void OnTcpReadable(cricket::PseudoTcp* tcp) OVERRIDE; | |
41 virtual void OnTcpWriteable(cricket::PseudoTcp* tcp) OVERRIDE; | |
42 // This is triggered by NotifyClock or NotifyPacket. | |
43 virtual void OnTcpClosed(cricket::PseudoTcp* tcp, uint32 error) OVERRIDE; | |
44 // This is triggered by NotifyClock, NotifyPacket, Recv and Send. | |
45 virtual WriteResult TcpWritePacket(cricket::PseudoTcp* tcp, | |
46 const char* buffer, size_t len) OVERRIDE; | |
47 | |
48 // "public" to avoid excessive boilerplate in PseudoTcpAdapter. | |
49 net::CompletionCallback* connect_callback_; | |
50 net::CompletionCallback* read_callback_; | |
51 net::CompletionCallback* write_callback_; | |
52 | |
53 cricket::PseudoTcp pseudo_tcp_; | |
54 private: | |
55 // These are invoked by the underlying Socket, and may trigger callbacks. | |
56 // They hold a reference to |this| while running, to protect from deletion. | |
57 void OnRead(int result); | |
58 void OnWritten(int result); | |
59 | |
60 // These may trigger callbacks, so the holder must hold a reference on | |
61 // the stack while calling them. | |
62 void DoReadFromSocket(); | |
63 void HandleReadResults(int result); | |
64 void HandleTcpClock(); | |
65 | |
66 // This re-sets |timer| without triggering callbacks. | |
67 void AdjustClock(); | |
68 | |
69 scoped_ptr<net::Socket> socket_; | |
70 | |
71 scoped_refptr<net::IOBuffer> read_buffer_; | |
72 int read_buffer_size_; | |
73 scoped_refptr<net::IOBuffer> write_buffer_; | |
74 int write_buffer_size_; | |
75 | |
76 bool socket_write_pending_; | |
77 scoped_refptr<net::IOBuffer> socket_read_buffer_; | |
78 | |
79 net::CompletionCallbackImpl<Core> socket_read_callback_; | |
80 net::CompletionCallbackImpl<Core> socket_write_callback_; | |
81 | |
82 base::OneShotTimer<Core> timer_; | |
83 | |
84 DISALLOW_COPY_AND_ASSIGN(Core); | |
85 }; | |
86 | |
87 | |
88 PseudoTcpAdapter::Core::Core(net::Socket* socket) | |
89 : connect_callback_(NULL), | |
28 read_callback_(NULL), | 90 read_callback_(NULL), |
29 write_callback_(NULL), | 91 write_callback_(NULL), |
92 ALLOW_THIS_IN_INITIALIZER_LIST(pseudo_tcp_(this, 0)), | |
93 socket_(socket), | |
30 socket_write_pending_(false), | 94 socket_write_pending_(false), |
31 ALLOW_THIS_IN_INITIALIZER_LIST( | 95 ALLOW_THIS_IN_INITIALIZER_LIST( |
32 socket_read_callback_(this, &PseudoTcpAdapter::OnRead)), | 96 socket_read_callback_(this, &PseudoTcpAdapter::Core::OnRead)), |
33 ALLOW_THIS_IN_INITIALIZER_LIST( | 97 ALLOW_THIS_IN_INITIALIZER_LIST( |
34 socket_write_callback_(this, &PseudoTcpAdapter::OnWritten)) { | 98 socket_write_callback_(this, &PseudoTcpAdapter::Core::OnWritten)) { |
35 pseudotcp_.NotifyMTU(kDefaultMtu); | 99 // Doesn't trigger callbacks. |
100 pseudo_tcp_.NotifyMTU(kDefaultMtu); | |
36 } | 101 } |
37 | 102 |
38 PseudoTcpAdapter::~PseudoTcpAdapter() { | 103 PseudoTcpAdapter::Core::~Core() { |
39 } | 104 } |
40 | 105 |
41 int PseudoTcpAdapter::Read(net::IOBuffer* buffer, int buffer_size, | 106 int PseudoTcpAdapter::Core::Read(net::IOBuffer* buffer, int buffer_size, |
42 net::CompletionCallback* callback) { | 107 net::CompletionCallback* callback) { |
43 DCHECK(CalledOnValidThread()); | 108 DCHECK(!read_callback_); |
44 | 109 |
45 // Verify that there is no other pending read. | 110 // Reference ourself in case callbacks result. |
46 DCHECK(read_callback_ == NULL); | 111 scoped_refptr<Core> core(this); |
47 | 112 |
48 PseudoTcp::TcpState state = pseudotcp_.State(); | 113 // TODO(wez): This is a hack for remoting. See JingleSession. |
114 PseudoTcp::TcpState state = pseudo_tcp_.State(); | |
49 int result; | 115 int result; |
50 if (state == PseudoTcp::TCP_SYN_SENT || | 116 if (state == PseudoTcp::TCP_SYN_SENT || |
51 state == PseudoTcp::TCP_SYN_RECEIVED) { | 117 state == PseudoTcp::TCP_SYN_RECEIVED) { |
52 result = net::ERR_IO_PENDING; | 118 result = net::ERR_IO_PENDING; |
119 | |
53 } else { | 120 } else { |
54 result = pseudotcp_.Recv(buffer->data(), buffer_size); | 121 result = pseudo_tcp_.Recv(buffer->data(), buffer_size); |
55 if (result < 0) { | 122 if (result < 0) { |
56 result = net::MapSystemError(pseudotcp_.GetError()); | 123 result = net::MapSystemError(pseudo_tcp_.GetError()); |
57 DCHECK(result < 0); | 124 DCHECK(result < 0); |
58 } | 125 } |
59 } | 126 } |
60 | 127 |
61 if (result == net::ERR_IO_PENDING) { | 128 if (result == net::ERR_IO_PENDING) { |
62 read_buffer_ = buffer; | 129 read_buffer_ = buffer; |
63 read_buffer_size_ = buffer_size; | 130 read_buffer_size_ = buffer_size; |
64 read_callback_ = callback; | 131 read_callback_ = callback; |
65 } | 132 } |
66 | 133 |
67 AdjustClock(); | 134 AdjustClock(); |
68 | 135 |
69 return result; | 136 return result; |
70 } | 137 } |
71 | 138 |
72 int PseudoTcpAdapter::Write(net::IOBuffer* buffer, int buffer_size, | 139 int PseudoTcpAdapter::Core::Write(net::IOBuffer* buffer, int buffer_size, |
73 net::CompletionCallback* callback) { | 140 net::CompletionCallback* callback) { |
74 DCHECK(CalledOnValidThread()); | 141 DCHECK(!write_callback_); |
75 | 142 |
76 // Verify that there is no other pending write. | 143 // Reference ourself in case callbacks result. |
Sergey Ulanov
2011/05/20 22:01:40
The comments doesn't seem to be complete.
Wez
2011/05/21 08:10:55
Done.
| |
77 DCHECK(write_callback_ == NULL); | 144 scoped_refptr<Core> core(this); |
78 | 145 |
79 PseudoTcp::TcpState state = pseudotcp_.State(); | 146 // TODO(wez): This is a hack for remoting. See JingleSession. |
147 PseudoTcp::TcpState state = pseudo_tcp_.State(); | |
80 int result; | 148 int result; |
81 if (state == PseudoTcp::TCP_SYN_SENT || | 149 if (state == PseudoTcp::TCP_SYN_SENT || |
82 state == PseudoTcp::TCP_SYN_RECEIVED) { | 150 state == PseudoTcp::TCP_SYN_RECEIVED) { |
83 result = net::ERR_IO_PENDING; | 151 result = net::ERR_IO_PENDING; |
152 | |
Sergey Ulanov
2011/05/20 22:01:40
Don't need this empty line
Wez
2011/05/21 08:10:55
It's there to mark the end of the block of code im
| |
84 } else { | 153 } else { |
85 result = pseudotcp_.Send(buffer->data(), buffer_size); | 154 result = pseudo_tcp_.Send(buffer->data(), buffer_size); |
86 if (result < 0) { | 155 if (result < 0) { |
87 result = net::MapSystemError(pseudotcp_.GetError()); | 156 result = net::MapSystemError(pseudo_tcp_.GetError()); |
88 DCHECK(result < 0); | 157 DCHECK(result < 0); |
89 } | 158 } |
90 } | 159 } |
91 | 160 |
92 if (result == net::ERR_IO_PENDING) { | 161 if (result == net::ERR_IO_PENDING) { |
93 write_buffer_ = buffer; | 162 write_buffer_ = buffer; |
94 write_buffer_size_ = buffer_size; | 163 write_buffer_size_ = buffer_size; |
95 write_callback_ = callback; | 164 write_callback_ = callback; |
96 } | 165 } |
97 | 166 |
98 AdjustClock(); | 167 AdjustClock(); |
99 | 168 |
100 return result; | 169 return result; |
101 } | 170 } |
102 | 171 |
103 bool PseudoTcpAdapter::SetReceiveBufferSize(int32 size) { | 172 int PseudoTcpAdapter::Core::Connect(net::CompletionCallback* callback) { |
104 DCHECK(CalledOnValidThread()); | 173 DCHECK_EQ(pseudo_tcp_.State(), cricket::PseudoTcp::TCP_LISTEN); |
105 // TODO(sergeyu): Implement support for adjustable buffer size and | |
106 // used it here. | |
107 return false; | |
108 } | |
109 | 174 |
110 bool PseudoTcpAdapter::SetSendBufferSize(int32 size) { | 175 // Reference ourself in case callbacks result. |
Sergey Ulanov
2011/05/20 22:01:40
The comments doesn't seem to be complete
Wez
2011/05/21 08:10:55
Done.
| |
111 DCHECK(CalledOnValidThread()); | 176 scoped_refptr<Core> core(this); |
112 // TODO(sergeyu): Implement support for adjustable buffer size and | |
113 // used it here. | |
114 return false; | |
115 } | |
116 | 177 |
117 int PseudoTcpAdapter::Connect(net::CompletionCallback* callback) { | 178 // Start the connection attempt. |
118 DCHECK(CalledOnValidThread()); | 179 int result = pseudo_tcp_.Connect(); |
119 | |
120 // Start reading from the socket. | |
121 DoReadFromSocket(); | |
122 | |
123 int result = pseudotcp_.Connect(); | |
124 if (result < 0) | 180 if (result < 0) |
125 return net::ERR_FAILED; | 181 return net::ERR_FAILED; |
126 | 182 |
127 AdjustClock(); | 183 AdjustClock(); |
128 | 184 |
129 connect_callback_ = callback; | 185 connect_callback_ = callback; |
186 DoReadFromSocket(); | |
187 | |
130 return net::ERR_IO_PENDING; | 188 return net::ERR_IO_PENDING; |
131 } | 189 } |
132 | 190 |
133 void PseudoTcpAdapter::Disconnect() { | 191 void PseudoTcpAdapter::Core::OnTcpOpen(PseudoTcp* tcp) { |
134 DCHECK(CalledOnValidThread()); | 192 DCHECK(tcp == &pseudo_tcp_); |
135 pseudotcp_.Close(false); | |
136 } | |
137 | 193 |
138 bool PseudoTcpAdapter::IsConnected() const { | 194 if (connect_callback_) { |
139 DCHECK(CalledOnValidThread()); | 195 net::CompletionCallback* callback = connect_callback_; |
140 return pseudotcp_.State() == PseudoTcp::TCP_ESTABLISHED; | 196 connect_callback_ = NULL; |
141 } | 197 callback->Run(net::OK); |
142 | 198 } |
143 bool PseudoTcpAdapter::IsConnectedAndIdle() const { | |
144 DCHECK(CalledOnValidThread()); | |
145 NOTIMPLEMENTED(); | |
146 return false; | |
147 } | |
148 | |
149 int PseudoTcpAdapter::GetPeerAddress(net::AddressList* address) const { | |
150 DCHECK(CalledOnValidThread()); | |
151 | |
152 // We actually don't know the peer address. Returning so the upper layers | |
153 // won't complain. | |
154 net::IPAddressNumber ip_address(4); | |
155 *address = net::AddressList::CreateFromIPAddress(ip_address, 0); | |
156 return net::OK; | |
157 } | |
158 | |
159 int PseudoTcpAdapter::GetLocalAddress(net::IPEndPoint* address) const { | |
160 DCHECK(CalledOnValidThread()); | |
161 NOTIMPLEMENTED(); | |
162 return net::ERR_FAILED; | |
163 } | |
164 | |
165 const net::BoundNetLog& PseudoTcpAdapter::NetLog() const { | |
166 DCHECK(CalledOnValidThread()); | |
167 return net_log_; | |
168 } | |
169 | |
170 void PseudoTcpAdapter::SetSubresourceSpeculation() { | |
171 DCHECK(CalledOnValidThread()); | |
172 NOTIMPLEMENTED(); | |
173 } | |
174 | |
175 void PseudoTcpAdapter::SetOmniboxSpeculation() { | |
176 DCHECK(CalledOnValidThread()); | |
177 NOTIMPLEMENTED(); | |
178 } | |
179 | |
180 bool PseudoTcpAdapter::WasEverUsed() const { | |
181 DCHECK(CalledOnValidThread()); | |
182 NOTIMPLEMENTED(); | |
183 return true; | |
184 } | |
185 | |
186 bool PseudoTcpAdapter::UsingTCPFastOpen() const { | |
187 DCHECK(CalledOnValidThread()); | |
188 return false; | |
189 } | |
190 | |
191 void PseudoTcpAdapter::OnTcpOpen(PseudoTcp* tcp) { | |
192 DCHECK(CalledOnValidThread()); | |
193 DCHECK(connect_callback_); | |
194 connect_callback_->Run(net::OK); | |
195 connect_callback_ = NULL; | |
196 | 199 |
197 OnTcpReadable(tcp); | 200 OnTcpReadable(tcp); |
198 OnTcpWriteable(tcp); | 201 OnTcpWriteable(tcp); |
199 } | 202 } |
200 | 203 |
201 void PseudoTcpAdapter::OnTcpReadable(PseudoTcp* tcp) { | 204 void PseudoTcpAdapter::Core::OnTcpReadable(PseudoTcp* tcp) { |
202 DCHECK(CalledOnValidThread()); | 205 DCHECK_EQ(tcp, &pseudo_tcp_); |
203 | |
204 if (!read_buffer_) | 206 if (!read_buffer_) |
Sergey Ulanov
2011/05/20 22:01:40
It's better to check for read_callback here and DC
Wez
2011/05/21 08:10:55
Done.
| |
205 return; | 207 return; |
206 | 208 |
207 // Try to send the data we have pending. | 209 int result = pseudo_tcp_.Recv(read_buffer_->data(), read_buffer_size_); |
208 int result = pseudotcp_.Recv(read_buffer_->data(), read_buffer_size_); | |
209 if (result < 0) { | 210 if (result < 0) { |
210 result = net::MapSystemError(pseudotcp_.GetError()); | 211 result = net::MapSystemError(pseudo_tcp_.GetError()); |
211 DCHECK(result < 0); | 212 DCHECK(result < 0); |
212 if (result == net::ERR_IO_PENDING) | 213 if (result == net::ERR_IO_PENDING) |
213 return; | 214 return; |
214 } | 215 } |
215 | 216 |
216 AdjustClock(); | 217 AdjustClock(); |
217 | 218 |
218 net::CompletionCallback* cb = read_callback_; | |
219 read_callback_ = NULL; | |
220 read_buffer_ = NULL; | 219 read_buffer_ = NULL; |
221 cb->Run(result); | 220 if (read_callback_) { |
Sergey Ulanov
2011/05/20 22:01:40
Don't think we need this if. if read_buffer_ is se
Wez
2011/05/21 08:10:55
Done.
| |
221 net::CompletionCallback* callback = read_callback_; | |
222 read_callback_ = NULL; | |
223 callback->Run(result); | |
224 } | |
222 } | 225 } |
223 | 226 |
224 void PseudoTcpAdapter::OnTcpWriteable(PseudoTcp* tcp) { | 227 void PseudoTcpAdapter::Core::OnTcpWriteable(PseudoTcp* tcp) { |
225 DCHECK(CalledOnValidThread()); | 228 DCHECK_EQ(tcp, &pseudo_tcp_); |
226 | |
227 if (!write_buffer_) | 229 if (!write_buffer_) |
228 return; | 230 return; |
229 | 231 |
230 // Try to send the data we have pending. | 232 int result = pseudo_tcp_.Send(write_buffer_->data(), write_buffer_size_); |
231 int result = pseudotcp_.Send(write_buffer_->data(), write_buffer_size_); | |
232 if (result < 0) { | 233 if (result < 0) { |
233 result = net::MapSystemError(pseudotcp_.GetError()); | 234 result = net::MapSystemError(pseudo_tcp_.GetError()); |
234 DCHECK(result < 0); | 235 DCHECK(result < 0); |
235 if (result == net::ERR_IO_PENDING) | 236 if (result == net::ERR_IO_PENDING) |
236 return; | 237 return; |
237 } | 238 } |
238 | 239 |
239 AdjustClock(); | 240 AdjustClock(); |
240 | 241 |
241 net::CompletionCallback* cb = write_callback_; | |
242 write_callback_ = NULL; | |
243 write_buffer_ = NULL; | 242 write_buffer_ = NULL; |
244 cb->Run(result); | 243 if (write_callback_) { |
Sergey Ulanov
2011/05/20 22:01:40
Same comment as for Read(): if there is data to wr
Wez
2011/05/21 08:10:55
Done.
| |
244 net::CompletionCallback* callback = write_callback_; | |
245 write_callback_ = NULL; | |
246 callback->Run(result); | |
247 } | |
245 } | 248 } |
246 | 249 |
247 void PseudoTcpAdapter::OnTcpClosed(PseudoTcp* tcp, uint32 error) { | 250 void PseudoTcpAdapter::Core::OnTcpClosed(PseudoTcp* tcp, uint32 error) { |
248 DCHECK(CalledOnValidThread()); | 251 DCHECK_EQ(tcp, &pseudo_tcp_); |
249 | 252 |
250 if (connect_callback_) { | 253 if (connect_callback_) { |
251 connect_callback_->Run(net::MapSystemError(error)); | 254 net::CompletionCallback* callback = connect_callback_; |
252 connect_callback_ = NULL; | 255 connect_callback_ = NULL; |
256 callback->Run(net::MapSystemError(error)); | |
253 } | 257 } |
254 | 258 |
255 if (read_callback_) { | 259 if (read_callback_) { |
256 read_callback_->Run(net::MapSystemError(error)); | 260 net::CompletionCallback* callback = read_callback_; |
257 read_callback_ = NULL; | 261 read_callback_ = NULL; |
262 callback->Run(net::MapSystemError(error)); | |
258 } | 263 } |
259 | 264 |
260 if (write_callback_) { | 265 if (write_callback_) { |
261 write_callback_->Run(net::MapSystemError(error)); | 266 net::CompletionCallback* callback = write_callback_; |
262 write_callback_ = NULL; | 267 write_callback_ = NULL; |
268 callback->Run(net::MapSystemError(error)); | |
263 } | 269 } |
264 } | 270 } |
265 | 271 |
266 cricket::IPseudoTcpNotify::WriteResult PseudoTcpAdapter::TcpWritePacket( | 272 cricket::IPseudoTcpNotify::WriteResult PseudoTcpAdapter::Core::TcpWritePacket( |
267 PseudoTcp* tcp, | 273 PseudoTcp* tcp, |
268 const char* buffer, | 274 const char* buffer, |
269 size_t len) { | 275 size_t len) { |
270 DCHECK(CalledOnValidThread()); | 276 DCHECK_EQ(tcp, &pseudo_tcp_); |
271 | 277 |
272 if (socket_write_pending_) | 278 if (socket_write_pending_) |
273 return IPseudoTcpNotify::WR_SUCCESS; | 279 return IPseudoTcpNotify::WR_SUCCESS; |
274 | 280 |
275 scoped_refptr<net::IOBuffer> write_buffer = new net::IOBuffer(len); | 281 scoped_refptr<net::IOBuffer> write_buffer = new net::IOBuffer(len); |
276 memcpy(write_buffer->data(), buffer, len); | 282 memcpy(write_buffer->data(), buffer, len); |
277 | 283 |
278 int result = socket_->Write(write_buffer, len, &socket_write_callback_); | 284 int result = socket_->Write(write_buffer, len, &socket_write_callback_); |
279 if (result == net::ERR_IO_PENDING) { | 285 if (result == net::ERR_IO_PENDING) { |
280 socket_write_pending_ = true; | 286 socket_write_pending_ = true; |
281 return IPseudoTcpNotify::WR_SUCCESS; | 287 return IPseudoTcpNotify::WR_SUCCESS; |
282 } if (result == net::ERR_MSG_TOO_BIG) { | 288 } if (result == net::ERR_MSG_TOO_BIG) { |
283 return IPseudoTcpNotify::WR_TOO_LARGE; | 289 return IPseudoTcpNotify::WR_TOO_LARGE; |
284 } else if (result < 0) { | 290 } else if (result < 0) { |
285 return IPseudoTcpNotify::WR_FAIL; | 291 return IPseudoTcpNotify::WR_FAIL; |
286 } else { | 292 } else { |
287 return IPseudoTcpNotify::WR_SUCCESS; | 293 return IPseudoTcpNotify::WR_SUCCESS; |
288 } | 294 } |
289 } | 295 } |
290 | 296 |
291 void PseudoTcpAdapter::DoReadFromSocket() { | 297 void PseudoTcpAdapter::Core::DoReadFromSocket() { |
292 if (!socket_read_buffer_) { | 298 if (!socket_read_buffer_) |
293 socket_read_buffer_ = new net::IOBuffer(kReadBufferSize); | 299 socket_read_buffer_ = new net::IOBuffer(kReadBufferSize); |
294 } | |
295 | 300 |
296 while (true) { | 301 while (true) { |
297 int result = socket_->Read(socket_read_buffer_, kReadBufferSize, | 302 int result = socket_->Read(socket_read_buffer_, kReadBufferSize, |
298 &socket_read_callback_); | 303 &socket_read_callback_); |
299 if (result == net::ERR_IO_PENDING) | 304 if (result == net::ERR_IO_PENDING) |
300 break; | 305 break; |
301 | 306 |
302 HandleReadResults(result); | 307 HandleReadResults(result); |
303 } | 308 } |
304 } | 309 } |
305 | 310 |
306 void PseudoTcpAdapter::HandleReadResults(int result) { | 311 void PseudoTcpAdapter::Core::HandleReadResults(int result) { |
307 if (result <= 0) { | 312 if (result <= 0) { |
308 LOG(ERROR) << "Read returned " << result; | 313 LOG(ERROR) << "Read returned " << result; |
309 return; | 314 return; |
310 } | 315 } |
311 | 316 |
312 pseudotcp_.NotifyPacket(socket_read_buffer_->data(), result); | 317 // TODO(wez): Disconnect on failure of NotifyPacket? |
318 pseudo_tcp_.NotifyPacket(socket_read_buffer_->data(), result); | |
313 AdjustClock(); | 319 AdjustClock(); |
314 } | 320 } |
315 | 321 |
316 void PseudoTcpAdapter::OnRead(int result) { | 322 void PseudoTcpAdapter::Core::OnRead(int result) { |
323 // Reference ourself in case callbacks result. | |
324 scoped_refptr<Core> core(this); | |
325 | |
317 HandleReadResults(result); | 326 HandleReadResults(result); |
318 if (result >= 0) | 327 if (result >= 0) |
319 DoReadFromSocket(); | 328 DoReadFromSocket(); |
320 } | 329 } |
321 | 330 |
322 void PseudoTcpAdapter::OnWritten(int result) { | 331 void PseudoTcpAdapter::Core::OnWritten(int result) { |
332 // Reference ourself in case callbacks result. | |
333 scoped_refptr<Core> core(this); | |
334 | |
323 socket_write_pending_ = false; | 335 socket_write_pending_ = false; |
324 if (result < 0) { | 336 if (result < 0) { |
325 LOG(WARNING) << "Write failed. Error code: " << result; | 337 LOG(WARNING) << "Write failed. Error code: " << result; |
326 } | 338 } |
327 } | 339 } |
328 | 340 |
329 void PseudoTcpAdapter::AdjustClock() { | 341 void PseudoTcpAdapter::Core::AdjustClock() { |
330 long timeout = 0; | 342 long timeout = 0; |
331 if (pseudotcp_.GetNextClock(PseudoTcp::Now(), timeout)) { | 343 if (pseudo_tcp_.GetNextClock(PseudoTcp::Now(), timeout)) { |
332 timer_.Stop(); | 344 timer_.Stop(); |
333 timer_.Start(base::TimeDelta::FromMilliseconds(std::max(timeout, 0L)), this, | 345 timer_.Start(base::TimeDelta::FromMilliseconds(std::max(timeout, 0L)), this, |
334 &PseudoTcpAdapter::HandleTcpClock); | 346 &PseudoTcpAdapter::Core::HandleTcpClock); |
335 } | 347 } |
336 } | 348 } |
337 | 349 |
338 void PseudoTcpAdapter::HandleTcpClock() { | 350 void PseudoTcpAdapter::Core::HandleTcpClock() { |
339 pseudotcp_.NotifyClock(PseudoTcp::Now()); | 351 // Reference ourself in case callbacks result. |
352 scoped_refptr<Core> core(this); | |
353 | |
354 pseudo_tcp_.NotifyClock(PseudoTcp::Now()); | |
340 AdjustClock(); | 355 AdjustClock(); |
341 } | 356 } |
342 | 357 |
358 // Public interface implemention. | |
359 | |
360 PseudoTcpAdapter::PseudoTcpAdapter(net::Socket* socket) | |
361 : core_(new Core(socket)) { | |
362 } | |
363 | |
364 PseudoTcpAdapter::~PseudoTcpAdapter() { | |
365 core_->connect_callback_ = NULL; | |
366 core_->read_callback_ = NULL; | |
367 core_->write_callback_ = NULL; | |
368 } | |
369 | |
370 int PseudoTcpAdapter::Read(net::IOBuffer* buffer, int buffer_size, | |
371 net::CompletionCallback* callback) { | |
372 DCHECK(CalledOnValidThread()); | |
373 return core_->Read(buffer, buffer_size, callback); | |
374 } | |
375 | |
376 int PseudoTcpAdapter::Write(net::IOBuffer* buffer, int buffer_size, | |
377 net::CompletionCallback* callback) { | |
378 DCHECK(CalledOnValidThread()); | |
379 return core_->Write(buffer, buffer_size, callback); | |
380 } | |
381 | |
382 bool PseudoTcpAdapter::SetReceiveBufferSize(int32 size) { | |
383 DCHECK(CalledOnValidThread()); | |
384 // TODO(sergeyu): Implement support for adjustable buffer size and | |
385 // used it here. | |
386 return false; | |
387 } | |
388 | |
389 bool PseudoTcpAdapter::SetSendBufferSize(int32 size) { | |
390 DCHECK(CalledOnValidThread()); | |
391 // TODO(sergeyu): Implement support for adjustable buffer size and | |
392 // used it here. | |
393 return false; | |
394 } | |
395 | |
396 int PseudoTcpAdapter::Connect(net::CompletionCallback* callback) { | |
397 DCHECK(CalledOnValidThread()); | |
398 | |
399 // net::StreamSocket requires that Connect return OK if already connected. | |
400 if (IsConnected()) | |
401 return net::OK; | |
402 | |
403 return core_->Connect(callback); | |
404 } | |
405 | |
406 void PseudoTcpAdapter::Disconnect() { | |
407 DCHECK(CalledOnValidThread()); | |
408 | |
409 // Don't dispatch outstanding callbacks, as mandated by net::StreamSocket. | |
410 core_->read_callback_ = NULL; | |
411 core_->write_callback_ = NULL; | |
412 core_->connect_callback_ = NULL; | |
413 | |
414 // TODO(wez): Connect should succeed if called after Disconnect, which | |
415 // PseudoTcp doesn't support, so we need to teardown the internal PseudoTcp | |
416 // and create a new one in Connect. | |
417 // TODO(wez): Close sets a shutdown flag inside PseudoTcp but has no other | |
418 // effect. This should be addressed in PseudoTcp, really. | |
419 // In the meantime we can fake OnTcpClosed notification and tear down the | |
420 // PseudoTcp. | |
421 // TODO(wez): The "force" parameter to Close() should be true, since the | |
422 // behaviour of disconnect is to dump any pending reads & writes. | |
423 core_->pseudo_tcp_.Close(false); | |
424 } | |
425 | |
426 bool PseudoTcpAdapter::IsConnected() const { | |
427 return core_->pseudo_tcp_.State() == PseudoTcp::TCP_ESTABLISHED; | |
428 } | |
429 | |
430 bool PseudoTcpAdapter::IsConnectedAndIdle() const { | |
431 DCHECK(CalledOnValidThread()); | |
432 NOTIMPLEMENTED(); | |
433 return false; | |
434 } | |
435 | |
436 int PseudoTcpAdapter::GetPeerAddress(net::AddressList* address) const { | |
437 DCHECK(CalledOnValidThread()); | |
438 | |
439 // We actually don't know the peer address. Returning so the upper layers | |
440 // won't complain. | |
441 net::IPAddressNumber ip_address(4); | |
442 *address = net::AddressList::CreateFromIPAddress(ip_address, 0); | |
443 return net::OK; | |
444 } | |
445 | |
446 int PseudoTcpAdapter::GetLocalAddress(net::IPEndPoint* address) const { | |
447 DCHECK(CalledOnValidThread()); | |
448 NOTIMPLEMENTED(); | |
449 return net::ERR_FAILED; | |
450 } | |
451 | |
452 const net::BoundNetLog& PseudoTcpAdapter::NetLog() const { | |
453 DCHECK(CalledOnValidThread()); | |
454 return net_log_; | |
455 } | |
456 | |
457 void PseudoTcpAdapter::SetSubresourceSpeculation() { | |
458 DCHECK(CalledOnValidThread()); | |
459 NOTIMPLEMENTED(); | |
460 } | |
461 | |
462 void PseudoTcpAdapter::SetOmniboxSpeculation() { | |
463 DCHECK(CalledOnValidThread()); | |
464 NOTIMPLEMENTED(); | |
465 } | |
466 | |
467 bool PseudoTcpAdapter::WasEverUsed() const { | |
468 DCHECK(CalledOnValidThread()); | |
469 NOTIMPLEMENTED(); | |
470 return true; | |
471 } | |
472 | |
473 bool PseudoTcpAdapter::UsingTCPFastOpen() const { | |
474 DCHECK(CalledOnValidThread()); | |
475 return false; | |
476 } | |
477 | |
343 } // namespace jingle_glue | 478 } // namespace jingle_glue |
OLD | NEW |