OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2004--2006, Google Inc. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright notice, | |
9 * this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 * this list of conditions and the following disclaimer in the documentation | |
12 * and/or other materials provided with the distribution. | |
13 * 3. The name of the author may not be used to endorse or promote products | |
14 * derived from this software without specific prior written permission. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 #include <algorithm> | |
29 #include <string> | |
30 | |
31 #include "pseudotcpchannel.h" | |
32 #include "webrtc/p2p/base/candidate.h" | |
33 #include "webrtc/p2p/base/transportchannel.h" | |
34 #include "webrtc/base/basictypes.h" | |
35 #include "webrtc/base/common.h" | |
36 #include "webrtc/base/logging.h" | |
37 #include "webrtc/base/scoped_ptr.h" | |
38 #include "webrtc/base/stringutils.h" | |
39 | |
40 using namespace rtc; | |
41 | |
42 namespace cricket { | |
43 | |
44 extern const rtc::ConstantLabel SESSION_STATES[]; | |
45 | |
46 // MSG_WK_* - worker thread messages | |
47 // MSG_ST_* - stream thread messages | |
48 // MSG_SI_* - signal thread messages | |
49 | |
50 enum { | |
51 MSG_WK_CLOCK = 1, | |
52 MSG_WK_PURGE, | |
53 MSG_ST_EVENT, | |
54 MSG_SI_DESTROYCHANNEL, | |
55 MSG_SI_DESTROY, | |
56 }; | |
57 | |
58 struct EventData : public MessageData { | |
59 int event, error; | |
60 EventData(int ev, int err = 0) : event(ev), error(err) { } | |
61 }; | |
62 | |
63 /////////////////////////////////////////////////////////////////////////////// | |
64 // PseudoTcpChannel::InternalStream | |
65 /////////////////////////////////////////////////////////////////////////////// | |
66 | |
67 class PseudoTcpChannel::InternalStream : public StreamInterface { | |
68 public: | |
69 InternalStream(PseudoTcpChannel* parent); | |
70 virtual ~InternalStream(); | |
71 | |
72 virtual StreamState GetState() const; | |
73 virtual StreamResult Read(void* buffer, size_t buffer_len, | |
74 size_t* read, int* error); | |
75 virtual StreamResult Write(const void* data, size_t data_len, | |
76 size_t* written, int* error); | |
77 virtual void Close(); | |
78 | |
79 private: | |
80 // parent_ is accessed and modified exclusively on the event thread, to | |
81 // avoid thread contention. This means that the PseudoTcpChannel cannot go | |
82 // away until after it receives a Close() from TunnelStream. | |
83 PseudoTcpChannel* parent_; | |
84 }; | |
85 | |
86 /////////////////////////////////////////////////////////////////////////////// | |
87 // PseudoTcpChannel | |
88 // Member object lifetime summaries: | |
89 // session_ - passed in constructor, cleared when channel_ goes away. | |
90 // channel_ - created in Connect, destroyed when session_ or tcp_ goes away. | |
91 // tcp_ - created in Connect, destroyed when channel_ goes away, or connection | |
92 // closes. | |
93 // worker_thread_ - created when channel_ is created, purged when channel_ is | |
94 // destroyed. | |
95 // stream_ - created in GetStream, destroyed by owner at arbitrary time. | |
96 // this - created in constructor, destroyed when worker_thread_ and stream_ | |
97 // are both gone. | |
98 /////////////////////////////////////////////////////////////////////////////// | |
99 | |
100 // | |
101 // Signal thread methods | |
102 // | |
103 | |
104 PseudoTcpChannel::PseudoTcpChannel(Thread* stream_thread, Session* session) | |
105 : signal_thread_(session->session_manager()->signaling_thread()), | |
106 worker_thread_(NULL), | |
107 stream_thread_(stream_thread), | |
108 session_(session), channel_(NULL), tcp_(NULL), stream_(NULL), | |
109 stream_readable_(false), pending_read_event_(false), | |
110 ready_to_connect_(false) { | |
111 ASSERT(signal_thread_->IsCurrent()); | |
112 ASSERT(NULL != session_); | |
113 } | |
114 | |
115 PseudoTcpChannel::~PseudoTcpChannel() { | |
116 ASSERT(signal_thread_->IsCurrent()); | |
117 ASSERT(worker_thread_ == NULL); | |
118 ASSERT(session_ == NULL); | |
119 ASSERT(channel_ == NULL); | |
120 ASSERT(stream_ == NULL); | |
121 ASSERT(tcp_ == NULL); | |
122 } | |
123 | |
124 bool PseudoTcpChannel::Connect(const std::string& content_name, | |
125 const std::string& channel_name, | |
126 int component) { | |
127 ASSERT(signal_thread_->IsCurrent()); | |
128 CritScope lock(&cs_); | |
129 | |
130 if (channel_) | |
131 return false; | |
132 | |
133 ASSERT(session_ != NULL); | |
134 worker_thread_ = session_->session_manager()->worker_thread(); | |
135 content_name_ = content_name; | |
136 channel_ = session_->CreateChannel( | |
137 content_name, channel_name, component); | |
138 channel_name_ = channel_name; | |
139 channel_->SetOption(Socket::OPT_DONTFRAGMENT, 1); | |
140 | |
141 channel_->SignalDestroyed.connect(this, | |
142 &PseudoTcpChannel::OnChannelDestroyed); | |
143 channel_->SignalWritableState.connect(this, | |
144 &PseudoTcpChannel::OnChannelWritableState); | |
145 channel_->SignalReadPacket.connect(this, | |
146 &PseudoTcpChannel::OnChannelRead); | |
147 channel_->SignalRouteChange.connect(this, | |
148 &PseudoTcpChannel::OnChannelConnectionChanged); | |
149 | |
150 ASSERT(tcp_ == NULL); | |
151 tcp_ = new PseudoTcp(this, 0); | |
152 if (session_->initiator()) { | |
153 // Since we may try several protocols and network adapters that won't work, | |
154 // waiting until we get our first writable notification before initiating | |
155 // TCP negotiation. | |
156 ready_to_connect_ = true; | |
157 } | |
158 | |
159 return true; | |
160 } | |
161 | |
162 StreamInterface* PseudoTcpChannel::GetStream() { | |
163 ASSERT(signal_thread_->IsCurrent()); | |
164 CritScope lock(&cs_); | |
165 ASSERT(NULL != session_); | |
166 if (!stream_) | |
167 stream_ = new PseudoTcpChannel::InternalStream(this); | |
168 //TODO("should we disallow creation of new stream at some point?"); | |
169 return stream_; | |
170 } | |
171 | |
172 void PseudoTcpChannel::OnChannelDestroyed(TransportChannel* channel) { | |
173 LOG_F(LS_INFO) << "(" << channel->component() << ")"; | |
174 ASSERT(signal_thread_->IsCurrent()); | |
175 CritScope lock(&cs_); | |
176 ASSERT(channel == channel_); | |
177 signal_thread_->Clear(this, MSG_SI_DESTROYCHANNEL); | |
178 // When MSG_WK_PURGE is received, we know there will be no more messages from | |
179 // the worker thread. | |
180 worker_thread_->Clear(this, MSG_WK_CLOCK); | |
181 worker_thread_->Post(this, MSG_WK_PURGE); | |
182 session_ = NULL; | |
183 channel_ = NULL; | |
184 if ((stream_ != NULL) | |
185 && ((tcp_ == NULL) || (tcp_->State() != PseudoTcp::TCP_CLOSED))) | |
186 stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, 0)); | |
187 if (tcp_) { | |
188 tcp_->Close(true); | |
189 AdjustClock(); | |
190 } | |
191 SignalChannelClosed(this); | |
192 } | |
193 | |
194 void PseudoTcpChannel::OnSessionTerminate(Session* session) { | |
195 // When the session terminates before we even connected | |
196 CritScope lock(&cs_); | |
197 if (session_ != NULL && channel_ == NULL) { | |
198 ASSERT(session == session_); | |
199 ASSERT(worker_thread_ == NULL); | |
200 ASSERT(tcp_ == NULL); | |
201 LOG(LS_INFO) << "Destroying unconnected PseudoTcpChannel"; | |
202 session_ = NULL; | |
203 if (stream_ != NULL) | |
204 stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, -1)); | |
205 } | |
206 | |
207 // Even though session_ is being destroyed, we mustn't clear the pointer, | |
208 // since we'll need it to tear down channel_. | |
209 // | |
210 // TODO: Is it always the case that if channel_ != NULL then we'll get | |
211 // a channel-destroyed notification? | |
212 } | |
213 | |
214 void PseudoTcpChannel::GetOption(PseudoTcp::Option opt, int* value) { | |
215 ASSERT(signal_thread_->IsCurrent()); | |
216 CritScope lock(&cs_); | |
217 ASSERT(tcp_ != NULL); | |
218 tcp_->GetOption(opt, value); | |
219 } | |
220 | |
221 void PseudoTcpChannel::SetOption(PseudoTcp::Option opt, int value) { | |
222 ASSERT(signal_thread_->IsCurrent()); | |
223 CritScope lock(&cs_); | |
224 ASSERT(tcp_ != NULL); | |
225 tcp_->SetOption(opt, value); | |
226 } | |
227 | |
228 // | |
229 // Stream thread methods | |
230 // | |
231 | |
232 StreamState PseudoTcpChannel::GetState() const { | |
233 ASSERT(stream_ != NULL && stream_thread_->IsCurrent()); | |
234 CritScope lock(&cs_); | |
235 if (!session_) | |
236 return SS_CLOSED; | |
237 if (!tcp_) | |
238 return SS_OPENING; | |
239 switch (tcp_->State()) { | |
240 case PseudoTcp::TCP_LISTEN: | |
241 case PseudoTcp::TCP_SYN_SENT: | |
242 case PseudoTcp::TCP_SYN_RECEIVED: | |
243 return SS_OPENING; | |
244 case PseudoTcp::TCP_ESTABLISHED: | |
245 return SS_OPEN; | |
246 case PseudoTcp::TCP_CLOSED: | |
247 default: | |
248 return SS_CLOSED; | |
249 } | |
250 } | |
251 | |
252 StreamResult PseudoTcpChannel::Read(void* buffer, size_t buffer_len, | |
253 size_t* read, int* error) { | |
254 ASSERT(stream_ != NULL && stream_thread_->IsCurrent()); | |
255 CritScope lock(&cs_); | |
256 if (!tcp_) | |
257 return SR_BLOCK; | |
258 | |
259 stream_readable_ = false; | |
260 int result = tcp_->Recv(static_cast<char*>(buffer), buffer_len); | |
261 //LOG_F(LS_VERBOSE) << "Recv returned: " << result; | |
262 if (result > 0) { | |
263 if (read) | |
264 *read = result; | |
265 // PseudoTcp doesn't currently support repeated Readable signals. Simulate | |
266 // them here. | |
267 stream_readable_ = true; | |
268 if (!pending_read_event_) { | |
269 pending_read_event_ = true; | |
270 stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_READ), true); | |
271 } | |
272 return SR_SUCCESS; | |
273 } else if (IsBlockingError(tcp_->GetError())) { | |
274 return SR_BLOCK; | |
275 } else { | |
276 if (error) | |
277 *error = tcp_->GetError(); | |
278 return SR_ERROR; | |
279 } | |
280 // This spot is never reached. | |
281 } | |
282 | |
283 StreamResult PseudoTcpChannel::Write(const void* data, size_t data_len, | |
284 size_t* written, int* error) { | |
285 ASSERT(stream_ != NULL && stream_thread_->IsCurrent()); | |
286 CritScope lock(&cs_); | |
287 if (!tcp_) | |
288 return SR_BLOCK; | |
289 int result = tcp_->Send(static_cast<const char*>(data), data_len); | |
290 //LOG_F(LS_VERBOSE) << "Send returned: " << result; | |
291 if (result > 0) { | |
292 if (written) | |
293 *written = result; | |
294 return SR_SUCCESS; | |
295 } else if (IsBlockingError(tcp_->GetError())) { | |
296 return SR_BLOCK; | |
297 } else { | |
298 if (error) | |
299 *error = tcp_->GetError(); | |
300 return SR_ERROR; | |
301 } | |
302 // This spot is never reached. | |
303 } | |
304 | |
305 void PseudoTcpChannel::Close() { | |
306 ASSERT(stream_ != NULL && stream_thread_->IsCurrent()); | |
307 CritScope lock(&cs_); | |
308 stream_ = NULL; | |
309 // Clear out any pending event notifications | |
310 stream_thread_->Clear(this, MSG_ST_EVENT); | |
311 if (tcp_) { | |
312 tcp_->Close(false); | |
313 AdjustClock(); | |
314 } else { | |
315 CheckDestroy(); | |
316 } | |
317 } | |
318 | |
319 // | |
320 // Worker thread methods | |
321 // | |
322 | |
323 void PseudoTcpChannel::OnChannelWritableState(TransportChannel* channel) { | |
324 LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]"; | |
325 ASSERT(worker_thread_->IsCurrent()); | |
326 CritScope lock(&cs_); | |
327 if (!channel_) { | |
328 LOG_F(LS_WARNING) << "NULL channel"; | |
329 return; | |
330 } | |
331 ASSERT(channel == channel_); | |
332 if (!tcp_) { | |
333 LOG_F(LS_WARNING) << "NULL tcp"; | |
334 return; | |
335 } | |
336 if (!ready_to_connect_ || !channel->writable()) | |
337 return; | |
338 | |
339 ready_to_connect_ = false; | |
340 tcp_->Connect(); | |
341 AdjustClock(); | |
342 } | |
343 | |
344 void PseudoTcpChannel::OnChannelRead(TransportChannel* channel, | |
345 const char* data, size_t size, | |
346 const rtc::PacketTime& packet_time, | |
347 int flags) { | |
348 //LOG_F(LS_VERBOSE) << "(" << size << ")"; | |
349 ASSERT(worker_thread_->IsCurrent()); | |
350 CritScope lock(&cs_); | |
351 if (!channel_) { | |
352 LOG_F(LS_WARNING) << "NULL channel"; | |
353 return; | |
354 } | |
355 ASSERT(channel == channel_); | |
356 if (!tcp_) { | |
357 LOG_F(LS_WARNING) << "NULL tcp"; | |
358 return; | |
359 } | |
360 tcp_->NotifyPacket(data, size); | |
361 AdjustClock(); | |
362 } | |
363 | |
364 void PseudoTcpChannel::OnChannelConnectionChanged(TransportChannel* channel, | |
365 const Candidate& candidate) { | |
366 LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]"; | |
367 ASSERT(worker_thread_->IsCurrent()); | |
368 CritScope lock(&cs_); | |
369 if (!channel_) { | |
370 LOG_F(LS_WARNING) << "NULL channel"; | |
371 return; | |
372 } | |
373 ASSERT(channel == channel_); | |
374 if (!tcp_) { | |
375 LOG_F(LS_WARNING) << "NULL tcp"; | |
376 return; | |
377 } | |
378 | |
379 uint16 mtu = 1280; // safe default | |
380 int family = candidate.address().family(); | |
381 Socket* socket = | |
382 worker_thread_->socketserver()->CreateAsyncSocket(family, SOCK_DGRAM); | |
383 rtc::scoped_ptr<Socket> mtu_socket(socket); | |
384 if (socket == NULL) { | |
385 LOG_F(LS_WARNING) << "Couldn't create socket while estimating MTU."; | |
386 } else { | |
387 if (mtu_socket->Connect(candidate.address()) < 0 || | |
388 mtu_socket->EstimateMTU(&mtu) < 0) { | |
389 LOG_F(LS_WARNING) << "Failed to estimate MTU, error=" | |
390 << mtu_socket->GetError(); | |
391 } | |
392 } | |
393 | |
394 LOG_F(LS_VERBOSE) << "Using MTU of " << mtu << " bytes"; | |
395 tcp_->NotifyMTU(mtu); | |
396 AdjustClock(); | |
397 } | |
398 | |
399 void PseudoTcpChannel::OnTcpOpen(PseudoTcp* tcp) { | |
400 LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]"; | |
401 ASSERT(cs_.CurrentThreadIsOwner()); | |
402 ASSERT(worker_thread_->IsCurrent()); | |
403 ASSERT(tcp == tcp_); | |
404 if (stream_) { | |
405 stream_readable_ = true; | |
406 pending_read_event_ = true; | |
407 stream_thread_->Post(this, MSG_ST_EVENT, | |
408 new EventData(SE_OPEN | SE_READ | SE_WRITE)); | |
409 } | |
410 } | |
411 | |
412 void PseudoTcpChannel::OnTcpReadable(PseudoTcp* tcp) { | |
413 //LOG_F(LS_VERBOSE); | |
414 ASSERT(cs_.CurrentThreadIsOwner()); | |
415 ASSERT(worker_thread_->IsCurrent()); | |
416 ASSERT(tcp == tcp_); | |
417 if (stream_) { | |
418 stream_readable_ = true; | |
419 if (!pending_read_event_) { | |
420 pending_read_event_ = true; | |
421 stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_READ)); | |
422 } | |
423 } | |
424 } | |
425 | |
426 void PseudoTcpChannel::OnTcpWriteable(PseudoTcp* tcp) { | |
427 //LOG_F(LS_VERBOSE); | |
428 ASSERT(cs_.CurrentThreadIsOwner()); | |
429 ASSERT(worker_thread_->IsCurrent()); | |
430 ASSERT(tcp == tcp_); | |
431 if (stream_) | |
432 stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_WRITE)); | |
433 } | |
434 | |
435 void PseudoTcpChannel::OnTcpClosed(PseudoTcp* tcp, uint32 nError) { | |
436 LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]"; | |
437 ASSERT(cs_.CurrentThreadIsOwner()); | |
438 ASSERT(worker_thread_->IsCurrent()); | |
439 ASSERT(tcp == tcp_); | |
440 if (stream_) | |
441 stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, nError)); | |
442 } | |
443 | |
444 // | |
445 // Multi-thread methods | |
446 // | |
447 | |
448 void PseudoTcpChannel::OnMessage(Message* pmsg) { | |
449 if (pmsg->message_id == MSG_WK_CLOCK) { | |
450 | |
451 ASSERT(worker_thread_->IsCurrent()); | |
452 //LOG(LS_INFO) << "PseudoTcpChannel::OnMessage(MSG_WK_CLOCK)"; | |
453 CritScope lock(&cs_); | |
454 if (tcp_) { | |
455 tcp_->NotifyClock(PseudoTcp::Now()); | |
456 AdjustClock(false); | |
457 } | |
458 | |
459 } else if (pmsg->message_id == MSG_WK_PURGE) { | |
460 | |
461 ASSERT(worker_thread_->IsCurrent()); | |
462 LOG_F(LS_INFO) << "(MSG_WK_PURGE)"; | |
463 // At this point, we know there are no additional worker thread messages. | |
464 CritScope lock(&cs_); | |
465 ASSERT(NULL == session_); | |
466 ASSERT(NULL == channel_); | |
467 worker_thread_ = NULL; | |
468 CheckDestroy(); | |
469 | |
470 } else if (pmsg->message_id == MSG_ST_EVENT) { | |
471 | |
472 ASSERT(stream_thread_->IsCurrent()); | |
473 //LOG(LS_INFO) << "PseudoTcpChannel::OnMessage(MSG_ST_EVENT, " | |
474 // << data->event << ", " << data->error << ")"; | |
475 ASSERT(stream_ != NULL); | |
476 EventData* data = static_cast<EventData*>(pmsg->pdata); | |
477 if (data->event & SE_READ) { | |
478 CritScope lock(&cs_); | |
479 pending_read_event_ = false; | |
480 } | |
481 stream_->SignalEvent(stream_, data->event, data->error); | |
482 delete data; | |
483 | |
484 } else if (pmsg->message_id == MSG_SI_DESTROYCHANNEL) { | |
485 | |
486 ASSERT(signal_thread_->IsCurrent()); | |
487 LOG_F(LS_INFO) << "(MSG_SI_DESTROYCHANNEL)"; | |
488 ASSERT(session_ != NULL); | |
489 ASSERT(channel_ != NULL); | |
490 session_->DestroyChannel(content_name_, channel_->component()); | |
491 | |
492 } else if (pmsg->message_id == MSG_SI_DESTROY) { | |
493 | |
494 ASSERT(signal_thread_->IsCurrent()); | |
495 LOG_F(LS_INFO) << "(MSG_SI_DESTROY)"; | |
496 // The message queue is empty, so it is safe to destroy ourselves. | |
497 delete this; | |
498 | |
499 } else { | |
500 ASSERT(false); | |
501 } | |
502 } | |
503 | |
504 IPseudoTcpNotify::WriteResult PseudoTcpChannel::TcpWritePacket( | |
505 PseudoTcp* tcp, const char* buffer, size_t len) { | |
506 ASSERT(cs_.CurrentThreadIsOwner()); | |
507 ASSERT(tcp == tcp_); | |
508 ASSERT(NULL != channel_); | |
509 rtc::PacketOptions packet_options; | |
510 int sent = channel_->SendPacket(buffer, len, packet_options); | |
511 if (sent > 0) { | |
512 //LOG_F(LS_VERBOSE) << "(" << sent << ") Sent"; | |
513 return IPseudoTcpNotify::WR_SUCCESS; | |
514 } else if (IsBlockingError(channel_->GetError())) { | |
515 LOG_F(LS_VERBOSE) << "Blocking"; | |
516 return IPseudoTcpNotify::WR_SUCCESS; | |
517 } else if (channel_->GetError() == EMSGSIZE) { | |
518 LOG_F(LS_ERROR) << "EMSGSIZE"; | |
519 return IPseudoTcpNotify::WR_TOO_LARGE; | |
520 } else { | |
521 PLOG(LS_ERROR, channel_->GetError()) << "PseudoTcpChannel::TcpWritePacket"; | |
522 ASSERT(false); | |
523 return IPseudoTcpNotify::WR_FAIL; | |
524 } | |
525 } | |
526 | |
527 void PseudoTcpChannel::AdjustClock(bool clear) { | |
528 ASSERT(cs_.CurrentThreadIsOwner()); | |
529 ASSERT(NULL != tcp_); | |
530 | |
531 long timeout = 0; | |
532 if (tcp_->GetNextClock(PseudoTcp::Now(), timeout)) { | |
533 ASSERT(NULL != channel_); | |
534 // Reset the next clock, by clearing the old and setting a new one. | |
535 if (clear) | |
536 worker_thread_->Clear(this, MSG_WK_CLOCK); | |
537 worker_thread_->PostDelayed(std::max(timeout, 0L), this, MSG_WK_CLOCK); | |
538 return; | |
539 } | |
540 | |
541 delete tcp_; | |
542 tcp_ = NULL; | |
543 ready_to_connect_ = false; | |
544 | |
545 if (channel_) { | |
546 // If TCP has failed, no need for channel_ anymore | |
547 signal_thread_->Post(this, MSG_SI_DESTROYCHANNEL); | |
548 } | |
549 } | |
550 | |
551 void PseudoTcpChannel::CheckDestroy() { | |
552 ASSERT(cs_.CurrentThreadIsOwner()); | |
553 if ((worker_thread_ != NULL) || (stream_ != NULL)) | |
554 return; | |
555 signal_thread_->Post(this, MSG_SI_DESTROY); | |
556 } | |
557 | |
558 /////////////////////////////////////////////////////////////////////////////// | |
559 // PseudoTcpChannel::InternalStream | |
560 /////////////////////////////////////////////////////////////////////////////// | |
561 | |
562 PseudoTcpChannel::InternalStream::InternalStream(PseudoTcpChannel* parent) | |
563 : parent_(parent) { | |
564 } | |
565 | |
566 PseudoTcpChannel::InternalStream::~InternalStream() { | |
567 Close(); | |
568 } | |
569 | |
570 StreamState PseudoTcpChannel::InternalStream::GetState() const { | |
571 if (!parent_) | |
572 return SS_CLOSED; | |
573 return parent_->GetState(); | |
574 } | |
575 | |
576 StreamResult PseudoTcpChannel::InternalStream::Read( | |
577 void* buffer, size_t buffer_len, size_t* read, int* error) { | |
578 if (!parent_) { | |
579 if (error) | |
580 *error = ENOTCONN; | |
581 return SR_ERROR; | |
582 } | |
583 return parent_->Read(buffer, buffer_len, read, error); | |
584 } | |
585 | |
586 StreamResult PseudoTcpChannel::InternalStream::Write( | |
587 const void* data, size_t data_len, size_t* written, int* error) { | |
588 if (!parent_) { | |
589 if (error) | |
590 *error = ENOTCONN; | |
591 return SR_ERROR; | |
592 } | |
593 return parent_->Write(data, data_len, written, error); | |
594 } | |
595 | |
596 void PseudoTcpChannel::InternalStream::Close() { | |
597 if (!parent_) | |
598 return; | |
599 parent_->Close(); | |
600 parent_ = NULL; | |
601 } | |
602 | |
603 /////////////////////////////////////////////////////////////////////////////// | |
604 | |
605 } // namespace cricket | |
OLD | NEW |