When Retrier succeeds, record errors it encountered.
[chromium-blink-merge.git] / tools / android / forwarder2 / forwarder.cc
blobd82bb0c3d6fa885f29eb11201f9b8b91d3cf6fe7
1 // Copyright (c) 2012 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.
5 #include "tools/android/forwarder2/forwarder.h"
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include "base/logging.h"
13 #include "base/posix/eintr_wrapper.h"
14 #include "base/safe_strerror_posix.h"
15 #include "tools/android/forwarder2/socket.h"
17 namespace forwarder2 {
19 namespace {
21 // Helper class to buffer reads and writes from one socket to another.
22 class BufferedCopier {
23 public:
24 // Does NOT own the pointers.
25 BufferedCopier(Socket* socket_from,
26 Socket* socket_to)
27 : socket_from_(socket_from),
28 socket_to_(socket_to),
29 bytes_read_(0),
30 write_offset_(0) {
33 bool AddToReadSet(fd_set* read_fds) {
34 if (bytes_read_ == 0)
35 return socket_from_->AddFdToSet(read_fds);
36 return false;
39 bool AddToWriteSet(fd_set* write_fds) {
40 if (write_offset_ < bytes_read_)
41 return socket_to_->AddFdToSet(write_fds);
42 return false;
45 bool TryRead(const fd_set& read_fds) {
46 if (!socket_from_->IsFdInSet(read_fds))
47 return false;
48 if (bytes_read_ != 0) // Can't read.
49 return false;
50 int ret = socket_from_->Read(buffer_, kBufferSize);
51 if (ret > 0) {
52 bytes_read_ = ret;
53 return true;
55 return false;
58 bool TryWrite(const fd_set& write_fds) {
59 if (!socket_to_->IsFdInSet(write_fds))
60 return false;
61 if (write_offset_ >= bytes_read_) // Nothing to write.
62 return false;
63 int ret = socket_to_->Write(buffer_ + write_offset_,
64 bytes_read_ - write_offset_);
65 if (ret > 0) {
66 write_offset_ += ret;
67 if (write_offset_ == bytes_read_) {
68 write_offset_ = 0;
69 bytes_read_ = 0;
71 return true;
73 return false;
76 private:
77 // Not owned.
78 Socket* socket_from_;
79 Socket* socket_to_;
81 // A big buffer to let our file-over-http bridge work more like real file.
82 static const int kBufferSize = 1024 * 128;
83 int bytes_read_;
84 int write_offset_;
85 char buffer_[kBufferSize];
87 DISALLOW_COPY_AND_ASSIGN(BufferedCopier);
90 } // namespace
92 Forwarder::Forwarder(scoped_ptr<Socket> socket1, scoped_ptr<Socket> socket2)
93 : socket1_(socket1.Pass()),
94 socket2_(socket2.Pass()) {
95 DCHECK(socket1_.get());
96 DCHECK(socket2_.get());
99 Forwarder::~Forwarder() {}
101 void Forwarder::Run() {
102 const int nfds = Socket::GetHighestFileDescriptor(*socket1_, *socket2_) + 1;
103 fd_set read_fds;
104 fd_set write_fds;
106 // Copy from socket1 to socket2
107 BufferedCopier buffer1(socket1_.get(), socket2_.get());
109 // Copy from socket2 to socket1
110 BufferedCopier buffer2(socket2_.get(), socket1_.get());
112 bool run = true;
113 while (run) {
114 FD_ZERO(&read_fds);
115 FD_ZERO(&write_fds);
117 buffer1.AddToReadSet(&read_fds);
118 buffer2.AddToReadSet(&read_fds);
119 buffer1.AddToWriteSet(&write_fds);
120 buffer2.AddToWriteSet(&write_fds);
122 if (HANDLE_EINTR(select(nfds, &read_fds, &write_fds, NULL, NULL)) <= 0) {
123 LOG(ERROR) << "Select error: " << safe_strerror(errno);
124 break;
126 // When a socket in the read set closes the connection, select() returns
127 // with that socket descriptor set as "ready to read". When we call
128 // TryRead() below, it will return false, but the while loop will continue
129 // to run until all the write operations are finished, to make sure the
130 // buffers are completely flushed out.
132 // Keep running while we have some operation to do.
133 run = buffer1.TryRead(read_fds);
134 run = run || buffer2.TryRead(read_fds);
135 run = run || buffer1.TryWrite(write_fds);
136 run = run || buffer2.TryWrite(write_fds);
139 delete this;
142 void Forwarder::Join() {
143 NOTREACHED() << "Can't Join a Forwarder thread.";
146 } // namespace forwarder