blob: c8a8302114a2e5f8e3fefe2cec7dc268edb032c0 [file] [log] [blame]
sergeyu7c4800b82015-02-26 18:02:491// Copyright 2015 The Chromium Authors. All rights reserved.
[email protected]c3af26f332010-10-06 22:46:002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
sergeyu7c4800b82015-02-26 18:02:495#include "remoting/base/buffered_socket_writer.h"
[email protected]c3af26f332010-10-06 22:46:006
[email protected]9e2a3132011-10-07 05:07:407#include "base/bind.h"
[email protected]7286e3fc2011-07-19 22:13:248#include "base/stl_util.h"
sergeyuaa22c082015-07-20 19:41:139#include "net/base/io_buffer.h"
[email protected]c3af26f332010-10-06 22:46:0010#include "net/base/net_errors.h"
sergeyuaa22c082015-07-20 19:41:1311#include "net/socket/socket.h"
[email protected]c3af26f332010-10-06 22:46:0012
13namespace remoting {
14
sergeyuaa22c082015-07-20 19:41:1315namespace {
16
17int WriteNetSocket(net::Socket* socket,
18 const scoped_refptr<net::IOBuffer>& buf,
19 int buf_len,
20 const net::CompletionCallback& callback) {
21 return socket->Write(buf.get(), buf_len, callback);
22}
23
24} // namespace
25
26struct BufferedSocketWriter::PendingPacket {
27 PendingPacket(scoped_refptr<net::DrainableIOBuffer> data,
[email protected]9e2a3132011-10-07 05:07:4028 const base::Closure& done_task)
[email protected]27626e62012-08-01 01:48:0229 : data(data),
30 done_task(done_task) {
[email protected]5bc71832010-12-09 01:34:0831 }
32
sergeyuaa22c082015-07-20 19:41:1333 scoped_refptr<net::DrainableIOBuffer> data;
[email protected]27626e62012-08-01 01:48:0234 base::Closure done_task;
[email protected]5bc71832010-12-09 01:34:0835};
36
sergeyuaa22c082015-07-20 19:41:1337// static
38scoped_ptr<BufferedSocketWriter> BufferedSocketWriter::CreateForSocket(
39 net::Socket* socket,
40 const WriteFailedCallback& write_failed_callback) {
41 scoped_ptr<BufferedSocketWriter> result(new BufferedSocketWriter());
42 result->Init(base::Bind(&WriteNetSocket, socket), write_failed_callback);
43 return result.Pass();
[email protected]c3af26f332010-10-06 22:46:0044}
45
sergeyuaa22c082015-07-20 19:41:1346BufferedSocketWriter::BufferedSocketWriter() : weak_factory_(this) {
[email protected]c3af26f332010-10-06 22:46:0047}
48
sergeyuaa22c082015-07-20 19:41:1349BufferedSocketWriter::~BufferedSocketWriter() {
50 STLDeleteElements(&queue_);
51}
52
53void BufferedSocketWriter::Init(
54 const WriteCallback& write_callback,
55 const WriteFailedCallback& write_failed_callback) {
56 write_callback_ = write_callback;
57 write_failed_callback_ = write_failed_callback;
58}
59
60bool BufferedSocketWriter::Write(
61 const scoped_refptr<net::IOBufferWithSize>& data,
62 const base::Closure& done_task) {
63 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]27626e62012-08-01 01:48:0264 DCHECK(data.get());
[email protected]a3464dca2012-05-24 01:27:0965
sergeyuaa22c082015-07-20 19:41:1366 // Don't write after error.
67 if (is_closed())
[email protected]a3464dca2012-05-24 01:27:0968 return false;
69
sergeyuaa22c082015-07-20 19:41:1370 queue_.push_back(new PendingPacket(
71 new net::DrainableIOBuffer(data.get(), data->size()), done_task));
[email protected]a3464dca2012-05-24 01:27:0972
73 DoWrite();
[email protected]dfcc8922012-08-08 02:03:1074
sergeyuaa22c082015-07-20 19:41:1375 return !is_closed();
[email protected]c3af26f332010-10-06 22:46:0076}
77
sergeyuaa22c082015-07-20 19:41:1378bool BufferedSocketWriter::is_closed() {
79 return write_callback_.is_null();
80}
[email protected]c3af26f332010-10-06 22:46:0081
sergeyuaa22c082015-07-20 19:41:1382void BufferedSocketWriter::DoWrite() {
83 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]c3af26f332010-10-06 22:46:0084
sergeyuaa22c082015-07-20 19:41:1385 base::WeakPtr<BufferedSocketWriter> self = weak_factory_.GetWeakPtr();
86 while (self && !write_pending_ && !is_closed() && !queue_.empty()) {
87 int result = write_callback_.Run(
88 queue_.front()->data.get(), queue_.front()->data->BytesRemaining(),
89 base::Bind(&BufferedSocketWriter::OnWritten,
90 weak_factory_.GetWeakPtr()));
91 HandleWriteResult(result);
[email protected]27626e62012-08-01 01:48:0292 }
93}
94
sergeyuaa22c082015-07-20 19:41:1395void BufferedSocketWriter::HandleWriteResult(int result) {
[email protected]27626e62012-08-01 01:48:0296 if (result < 0) {
97 if (result == net::ERR_IO_PENDING) {
98 write_pending_ = true;
[email protected]c3af26f332010-10-06 22:46:0099 } else {
sergeyuaa22c082015-07-20 19:41:13100 write_callback_.Reset();
101 if (!write_failed_callback_.is_null()) {
102 WriteFailedCallback callback = write_failed_callback_;
103 callback.Run(result);
104 }
[email protected]27626e62012-08-01 01:48:02105 }
106 return;
107 }
108
sergeyuaa22c082015-07-20 19:41:13109 DCHECK(!queue_.empty());
[email protected]27626e62012-08-01 01:48:02110
sergeyuaa22c082015-07-20 19:41:13111 queue_.front()->data->DidConsume(result);
112
113 if (queue_.front()->data->BytesRemaining() == 0) {
114 base::Closure done_task = queue_.front()->done_task;
115 delete queue_.front();
116 queue_.pop_front();
117
118 if (!done_task.is_null())
119 done_task.Run();
120 }
[email protected]c3af26f332010-10-06 22:46:00121}
122
sergeyuaa22c082015-07-20 19:41:13123void BufferedSocketWriter::OnWritten(int result) {
124 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]27626e62012-08-01 01:48:02125 DCHECK(write_pending_);
[email protected]c3af26f332010-10-06 22:46:00126 write_pending_ = false;
127
sergeyuaa22c082015-07-20 19:41:13128 base::WeakPtr<BufferedSocketWriter> self = weak_factory_.GetWeakPtr();
129 HandleWriteResult(result);
130 if (self)
[email protected]27626e62012-08-01 01:48:02131 DoWrite();
[email protected]c3af26f332010-10-06 22:46:00132}
133
[email protected]c3af26f332010-10-06 22:46:00134} // namespace remoting