diff options
Diffstat (limited to 'remoting/jingle_glue/jingle_channel.cc')
-rw-r--r-- | remoting/jingle_glue/jingle_channel.cc | 65 |
1 files changed, 50 insertions, 15 deletions
diff --git a/remoting/jingle_glue/jingle_channel.cc b/remoting/jingle_glue/jingle_channel.cc index 0ff634c..9dc545f 100644 --- a/remoting/jingle_glue/jingle_channel.cc +++ b/remoting/jingle_glue/jingle_channel.cc @@ -22,6 +22,7 @@ const size_t kReadBufferSize = 4096; JingleChannel::JingleChannel(Callback* callback) : state_(INITIALIZING), callback_(callback), + closed_(false), event_handler_(this), write_buffer_size_(0), current_write_buf_pos_(0) { @@ -31,12 +32,13 @@ JingleChannel::JingleChannel(Callback* callback) // This constructor is only used in unit test. JingleChannel::JingleChannel() : state_(CLOSED), + closed_(false), write_buffer_size_(0), current_write_buf_pos_(0) { } JingleChannel::~JingleChannel() { - DCHECK_EQ(CLOSED, state_); + DCHECK(closed_ || stream_ == NULL); } void JingleChannel::Init(JingleThread* thread, @@ -101,7 +103,12 @@ void JingleChannel::DoRead() { case talk_base::SR_SUCCESS: { DCHECK_GT(bytes_read, 0U); buffer->SetDataSize(bytes_read); - callback_->OnPacketReceived(this, buffer); + { + AutoLock auto_lock(state_lock_); + // Drop received data if the channel is already closed. + if (!closed_) + callback_->OnPacketReceived(this, buffer); + } break; } case talk_base::SR_BLOCK: { @@ -177,25 +184,53 @@ void JingleChannel::OnStreamEvent(talk_base::StreamInterface* stream, SetState(CLOSED); } -void JingleChannel::SetState(State state) { - if (state == state_) - return; - state_ = state; - callback_->OnStateChange(this, state); +void JingleChannel::SetState(State new_state) { + if (new_state != state_) { + state_ = new_state; + { + AutoLock auto_lock(state_lock_); + if (!closed_) + callback_->OnStateChange(this, new_state); + } + } } void JingleChannel::Close() { - base::WaitableEvent event(true, false); + Close(NULL); +} + +void JingleChannel::Close(Task* closed_task) { + { + AutoLock auto_lock(state_lock_); + if (closed_) { + // We are already closed. + if (closed_task) + thread_->message_loop()->PostTask(FROM_HERE, closed_task); + return; + } + closed_ = true; + if (closed_task) + closed_task_.reset(closed_task); + } + thread_->message_loop()->PostTask( - FROM_HERE, NewRunnableMethod(this, &JingleChannel::DoClose, &event)); - event.Wait(); + FROM_HERE, NewRunnableMethod(this, &JingleChannel::DoClose)); } -void JingleChannel::DoClose(base::WaitableEvent* done_event) { - if (stream_.get()) - stream_->Close(); - SetState(CLOSED); - done_event->Signal(); + +void JingleChannel::DoClose() { + DCHECK(closed_); + stream_->Close(); + stream_.reset(); + + // TODO(sergeyu): Even though we have called Close() for the stream, it + // doesn't mean that the p2p sessions has been closed. I.e. |closed_task_| + // is called too early. If the client is closed right after that the other + // side will not receive notification that the channel was closed. + if (closed_task_.get()) { + closed_task_->Run(); + closed_task_.reset(); + } } size_t JingleChannel::write_buffer_size() { |