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"
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
{
21 // Helper class to buffer reads and writes from one socket to another.
22 class BufferedCopier
{
24 // Does NOT own the pointers.
25 BufferedCopier(Socket
* socket_from
,
27 : socket_from_(socket_from
),
28 socket_to_(socket_to
),
33 bool AddToReadSet(fd_set
* read_fds
) {
35 return socket_from_
->AddFdToSet(read_fds
);
39 bool AddToWriteSet(fd_set
* write_fds
) {
40 if (write_offset_
< bytes_read_
)
41 return socket_to_
->AddFdToSet(write_fds
);
45 bool TryRead(const fd_set
& read_fds
) {
46 if (!socket_from_
->IsFdInSet(read_fds
))
48 if (bytes_read_
!= 0) // Can't read.
50 int ret
= socket_from_
->Read(buffer_
, kBufferSize
);
58 bool TryWrite(const fd_set
& write_fds
) {
59 if (!socket_to_
->IsFdInSet(write_fds
))
61 if (write_offset_
>= bytes_read_
) // Nothing to write.
63 int ret
= socket_to_
->Write(buffer_
+ write_offset_
,
64 bytes_read_
- write_offset_
);
67 if (write_offset_
== bytes_read_
) {
81 // A big buffer to let our file-over-http bridge work more like real file.
82 static const int kBufferSize
= 1024 * 128;
85 char buffer_
[kBufferSize
];
87 DISALLOW_COPY_AND_ASSIGN(BufferedCopier
);
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;
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());
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
);
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
);
142 void Forwarder::Join() {
143 NOTREACHED() << "Can't Join a Forwarder thread.";
146 } // namespace forwarder