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 "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/posix/eintr_wrapper.h"
10 #include "tools/android/forwarder2/socket.h"
12 namespace forwarder2
{
15 const int kBufferSize
= 32 * 1024;
20 // Helper class to buffer reads and writes from one socket to another.
21 // Each implements a small buffer connected two one input socket, and
24 // socket_from_ ---> [BufferedCopier] ---> socket_to_
26 // These objects are used in a pair to handle duplex traffic, as in:
28 // ------> [BufferedCopier_1] --->
30 // socket_1 * * socket_2
32 // <------ [BufferedCopier_2] <----
34 // When a BufferedCopier is in the READING state (see below), it only listens
35 // to events on its input socket, and won't detect when its output socket
36 // disconnects. To work around this, its peer will call its Close() method
39 class Forwarder::BufferedCopier
{
42 // READING - Empty buffer and Waiting for input.
43 // WRITING - Data in buffer, and waiting for output.
44 // CLOSING - Like WRITING, but do not try to read after that.
45 // CLOSED - Completely closed.
47 // State transitions are:
49 // T01: READING ---[receive data]---> WRITING
50 // T02: READING ---[error on input socket]---> CLOSED
51 // T03: READING ---[Close() call]---> CLOSED
53 // T04: WRITING ---[write partial data]---> WRITING
54 // T05: WRITING ---[write all data]----> READING
55 // T06: WRITING ---[error on output socket]----> CLOSED
56 // T07: WRITING ---[Close() call]---> CLOSING
58 // T08: CLOSING ---[write partial data]---> CLOSING
59 // T09: CLOSING ---[write all data]----> CLOSED
60 // T10: CLOSING ---[Close() call]---> CLOSING
61 // T11: CLOSING ---[error on output socket] ---> CLOSED
70 // Does NOT own the pointers.
71 BufferedCopier(Socket
* socket_from
, Socket
* socket_to
)
72 : socket_from_(socket_from
),
73 socket_to_(socket_to
),
77 state_(STATE_READING
) {}
79 // Sets the 'peer_' field pointing to the other BufferedCopier in a pair.
80 void SetPeer(BufferedCopier
* peer
) {
85 bool is_closed() const { return state_
== STATE_CLOSED
; }
87 // Gently asks to close a buffer. Called either by the peer or the forwarder.
91 state_
= STATE_CLOSED
; // T03
94 state_
= STATE_CLOSING
; // T07
103 // Call this before select(). This updates |read_fds|,
104 // |write_fds| and |max_fd| appropriately *if* the buffer isn't closed.
105 void PrepareSelect(fd_set
* read_fds
, fd_set
* write_fds
, int* max_fd
) {
109 DCHECK(bytes_read_
== 0);
110 DCHECK(write_offset_
== 0);
111 fd
= socket_from_
->fd();
116 FD_SET(fd
, read_fds
);
121 DCHECK(bytes_read_
> 0);
122 DCHECK(write_offset_
< bytes_read_
);
123 fd
= socket_to_
->fd();
128 FD_SET(fd
, write_fds
);
134 *max_fd
= std::max(*max_fd
, fd
);
137 // Call this after a select() call to operate over the buffer.
138 void ProcessSelect(const fd_set
& read_fds
, const fd_set
& write_fds
) {
142 fd
= socket_from_
->fd();
144 state_
= STATE_CLOSED
; // T02
147 if (!FD_ISSET(fd
, &read_fds
))
150 ret
= socket_from_
->NonBlockingRead(buffer_
, kBufferSize
);
157 state_
= STATE_WRITING
; // T01
162 fd
= socket_to_
->fd();
164 ForceClose(); // T06 + T11
167 if (!FD_ISSET(fd
, &write_fds
))
170 ret
= socket_to_
->NonBlockingWrite(buffer_
+ write_offset_
,
171 bytes_read_
- write_offset_
);
173 ForceClose(); // T06 + T11
177 write_offset_
+= ret
;
178 if (write_offset_
< bytes_read_
)
183 if (state_
== STATE_CLOSING
) {
187 state_
= STATE_READING
; // T05
196 // Internal method used to close the buffer and notify the peer, if any.
202 state_
= STATE_CLOSED
;
206 Socket
* socket_from_
;
211 BufferedCopier
* peer_
;
213 char buffer_
[kBufferSize
];
215 DISALLOW_COPY_AND_ASSIGN(BufferedCopier
);
218 Forwarder::Forwarder(scoped_ptr
<Socket
> socket1
,
219 scoped_ptr
<Socket
> socket2
)
220 : socket1_(socket1
.Pass()),
221 socket2_(socket2
.Pass()),
222 buffer1_(new BufferedCopier(socket1_
.get(), socket2_
.get())),
223 buffer2_(new BufferedCopier(socket2_
.get(), socket1_
.get())) {
224 buffer1_
->SetPeer(buffer2_
.get());
225 buffer2_
->SetPeer(buffer1_
.get());
228 Forwarder::~Forwarder() {
229 DCHECK(thread_checker_
.CalledOnValidThread());
232 void Forwarder::RegisterFDs(fd_set
* read_fds
, fd_set
* write_fds
, int* max_fd
) {
233 DCHECK(thread_checker_
.CalledOnValidThread());
234 buffer1_
->PrepareSelect(read_fds
, write_fds
, max_fd
);
235 buffer2_
->PrepareSelect(read_fds
, write_fds
, max_fd
);
238 void Forwarder::ProcessEvents(const fd_set
& read_fds
, const fd_set
& write_fds
) {
239 DCHECK(thread_checker_
.CalledOnValidThread());
240 buffer1_
->ProcessSelect(read_fds
, write_fds
);
241 buffer2_
->ProcessSelect(read_fds
, write_fds
);
244 bool Forwarder::IsClosed() const {
245 DCHECK(thread_checker_
.CalledOnValidThread());
246 return buffer1_
->is_closed() && buffer2_
->is_closed();
249 void Forwarder::Shutdown() {
250 DCHECK(thread_checker_
.CalledOnValidThread());
255 } // namespace forwarder2