blob: 6c60a4a6600bb30292f8c73c5c7bd0206abe1548 [file] [log] [blame]
[email protected]c3af26f332010-10-06 22:46:001// Copyright (c) 2010 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 "remoting/protocol/buffered_socket_writer.h"
6
7#include "base/message_loop.h"
8#include "net/base/net_errors.h"
9
10namespace remoting {
11
12BufferedSocketWriter::BufferedSocketWriter()
13 : socket_(NULL),
14 message_loop_(NULL),
15 buffer_size_(0),
16 write_pending_(false),
17 ALLOW_THIS_IN_INITIALIZER_LIST(
18 written_callback_(this, &BufferedSocketWriter::OnWritten)),
19 closed_(false) {
20}
21
22BufferedSocketWriter::~BufferedSocketWriter() { }
23
24void BufferedSocketWriter::Init(net::Socket* socket,
25 WriteFailedCallback* callback) {
26 AutoLock auto_lock(lock_);
27 message_loop_ = MessageLoop::current();
28 socket_ = socket;
29}
30
31bool BufferedSocketWriter::Write(scoped_refptr<net::IOBufferWithSize> data) {
32 AutoLock auto_lock(lock_);
33 if (!socket_)
34 return false;
35 queue_.push_back(data);
36 buffer_size_ += data->size();
37 message_loop_->PostTask(
38 FROM_HERE, NewRunnableMethod(this, &BufferedSocketWriter::DoWrite));
39 return true;
40}
41
42void BufferedSocketWriter::DoWrite() {
43 DCHECK_EQ(message_loop_, MessageLoop::current());
44 DCHECK(socket_);
45
46 // Don't try to write if the writer not initialized or closed, or
47 // there is already a write pending.
48 if (write_pending_ || closed_)
49 return;
50
51 while (true) {
52 while (!current_buf_ || current_buf_->BytesRemaining() == 0) {
53 AutoLock auto_lock(lock_);
54 if (queue_.empty())
55 return; // Nothing to write.
56 current_buf_ =
57 new net::DrainableIOBuffer(queue_.front(), queue_.front()->size());
58 queue_.pop_front();
59 }
60
61 int result = socket_->Write(current_buf_, current_buf_->BytesRemaining(),
62 &written_callback_);
63 if (result >= 0) {
64 {
65 AutoLock auto_lock(lock_);
66 buffer_size_ -= result;
67 }
68 current_buf_->DidConsume(result);
69 } else {
70 if (result == net::ERR_IO_PENDING) {
71 write_pending_ = true;
72 } else {
73 if (write_failed_callback_.get())
74 write_failed_callback_->Run(result);
75 }
76
77 return;
78 }
79 }
80}
81
82void BufferedSocketWriter::OnWritten(int result) {
83 DCHECK_EQ(message_loop_, MessageLoop::current());
84 write_pending_ = false;
85
86 if (result < 0) {
87 if (write_failed_callback_.get())
88 write_failed_callback_->Run(result);
89 }
90
91 {
92 AutoLock auto_lock(lock_);
93 buffer_size_ -= result;
94 }
95 current_buf_->DidConsume(result);
96 // Schedule next write.
97 message_loop_->PostTask(
98 FROM_HERE, NewRunnableMethod(this, &BufferedSocketWriter::DoWrite));
99}
100
101int BufferedSocketWriter::GetBufferSize() {
102 AutoLock auto_lock(lock_);
103 return buffer_size_;
104}
105
106int BufferedSocketWriter::GetBufferChunks() {
107 AutoLock auto_lock(lock_);
108 return queue_.size();
109}
110
111void BufferedSocketWriter::Close() {
112 AutoLock auto_lock(lock_);
113 closed_ = true;
114}
115
116} // namespace remoting