OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/android/forwarder2/forwarder.h" | 5 #include "tools/android/forwarder2/forwarder.h" |
6 | 6 |
7 #include <errno.h> | 7 #include "base/basictypes.h" |
8 #include <stdio.h> | 8 #include "base/bind.h" |
9 #include <stdlib.h> | |
10 #include <string.h> | |
11 | |
12 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/ref_counted.h" | |
13 #include "base/posix/eintr_wrapper.h" | 11 #include "base/posix/eintr_wrapper.h" |
14 #include "base/safe_strerror_posix.h" | 12 #include "base/single_thread_task_runner.h" |
15 #include "tools/android/forwarder2/socket.h" | 13 #include "tools/android/forwarder2/socket.h" |
16 | 14 |
17 namespace forwarder2 { | 15 namespace forwarder2 { |
18 | |
19 namespace { | 16 namespace { |
20 | 17 |
21 // Helper class to buffer reads and writes from one socket to another. | 18 // Helper class to buffer reads and writes from one socket to another. |
22 class BufferedCopier { | 19 class BufferedCopier { |
23 public: | 20 public: |
24 // Does NOT own the pointers. | 21 // Does NOT own the pointers. |
25 BufferedCopier(Socket* socket_from, | 22 BufferedCopier(Socket* socket_from, |
26 Socket* socket_to) | 23 Socket* socket_to) |
27 : socket_from_(socket_from), | 24 : socket_from_(socket_from), |
28 socket_to_(socket_to), | 25 socket_to_(socket_to), |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 Socket* socket_to_; | 76 Socket* socket_to_; |
80 | 77 |
81 // A big buffer to let our file-over-http bridge work more like real file. | 78 // A big buffer to let our file-over-http bridge work more like real file. |
82 static const int kBufferSize = 1024 * 128; | 79 static const int kBufferSize = 1024 * 128; |
83 int bytes_read_; | 80 int bytes_read_; |
84 int write_offset_; | 81 int write_offset_; |
85 char buffer_[kBufferSize]; | 82 char buffer_[kBufferSize]; |
86 | 83 |
87 DISALLOW_COPY_AND_ASSIGN(BufferedCopier); | 84 DISALLOW_COPY_AND_ASSIGN(BufferedCopier); |
88 }; | 85 }; |
89 | 86 |
digit1
2013/07/18 20:08:39
I'd recommend adding a comment explaining what the
Philippe
2013/07/22 15:16:14
Thanks :) I'm not completely sure what you meant w
| |
87 class Forwarder { | |
88 public: | |
89 Forwarder(scoped_ptr<Socket> socket1, scoped_ptr<Socket> socket2) | |
90 : socket1_(socket1.Pass()), | |
91 socket2_(socket2.Pass()), | |
92 destructor_runner_(base::MessageLoopProxy::current()), | |
93 thread_("ForwarderThread") { | |
94 } | |
95 | |
96 // Self-deletes. | |
97 ~Forwarder() {} | |
98 | |
99 void Start() { | |
100 thread_.Start(); | |
101 thread_.message_loop_proxy()->PostTask( | |
102 FROM_HERE, | |
103 base::Bind(&Forwarder::ThreadHandler, base::Unretained(this))); | |
104 } | |
105 | |
106 private: | |
107 void ThreadHandler() { | |
108 const int nfds = Socket::GetHighestFileDescriptor(*socket1_, *socket2_) + 1; | |
109 fd_set read_fds; | |
110 fd_set write_fds; | |
111 | |
112 // Copy from socket1 to socket2 | |
113 BufferedCopier buffer1(socket1_.get(), socket2_.get()); | |
114 // Copy from socket2 to socket1 | |
115 BufferedCopier buffer2(socket2_.get(), socket1_.get()); | |
116 | |
117 bool run = true; | |
118 while (run) { | |
119 FD_ZERO(&read_fds); | |
120 FD_ZERO(&write_fds); | |
121 | |
122 buffer1.AddToReadSet(&read_fds); | |
123 buffer2.AddToReadSet(&read_fds); | |
124 buffer1.AddToWriteSet(&write_fds); | |
125 buffer2.AddToWriteSet(&write_fds); | |
126 | |
127 if (HANDLE_EINTR(select(nfds, &read_fds, &write_fds, NULL, NULL)) <= 0) { | |
128 PLOG(ERROR) << "select"; | |
129 break; | |
130 } | |
131 // When a socket in the read set closes the connection, select() returns | |
132 // with that socket descriptor set as "ready to read". When we call | |
133 // TryRead() below, it will return false, but the while loop will continue | |
134 // to run until all the write operations are finished, to make sure the | |
135 // buffers are completely flushed out. | |
136 | |
137 // Keep running while we have some operation to do. | |
138 run = buffer1.TryRead(read_fds); | |
139 run = run || buffer2.TryRead(read_fds); | |
140 run = run || buffer1.TryWrite(write_fds); | |
141 run = run || buffer2.TryWrite(write_fds); | |
142 } | |
143 | |
144 // Note that the thread that |destruction_runner_| runs tasks on could be | |
145 // temporarily blocked on I/O (e.g. select()) therefore it is safer to close | |
146 // the sockets now rather than relying on the destructor. | |
147 socket1_.reset(); | |
148 socket2_.reset(); | |
149 | |
150 destructor_runner_->DeleteSoon(FROM_HERE, this); | |
151 } | |
152 | |
153 scoped_ptr<Socket> socket1_; | |
154 scoped_ptr<Socket> socket2_; | |
155 scoped_refptr<base::SingleThreadTaskRunner> destructor_runner_; | |
156 base::Thread thread_; | |
157 }; | |
158 | |
90 } // namespace | 159 } // namespace |
91 | 160 |
92 Forwarder::Forwarder(scoped_ptr<Socket> socket1, scoped_ptr<Socket> socket2) | 161 void StartForwarder(scoped_ptr<Socket> socket1, scoped_ptr<Socket> socket2) { |
93 : socket1_(socket1.Pass()), | 162 (new Forwarder(socket1.Pass(), socket2.Pass()))->Start(); |
94 socket2_(socket2.Pass()) { | |
95 DCHECK(socket1_.get()); | |
96 DCHECK(socket2_.get()); | |
97 } | 163 } |
98 | 164 |
99 Forwarder::~Forwarder() { | 165 } // namespace forwarder2 |
100 Detach(); | |
101 } | |
102 | |
103 void Forwarder::Run() { | |
104 const int nfds = Socket::GetHighestFileDescriptor(*socket1_, *socket2_) + 1; | |
105 fd_set read_fds; | |
106 fd_set write_fds; | |
107 | |
108 // Copy from socket1 to socket2 | |
109 BufferedCopier buffer1(socket1_.get(), socket2_.get()); | |
110 | |
111 // Copy from socket2 to socket1 | |
112 BufferedCopier buffer2(socket2_.get(), socket1_.get()); | |
113 | |
114 bool run = true; | |
115 while (run) { | |
116 FD_ZERO(&read_fds); | |
117 FD_ZERO(&write_fds); | |
118 | |
119 buffer1.AddToReadSet(&read_fds); | |
120 buffer2.AddToReadSet(&read_fds); | |
121 buffer1.AddToWriteSet(&write_fds); | |
122 buffer2.AddToWriteSet(&write_fds); | |
123 | |
124 if (HANDLE_EINTR(select(nfds, &read_fds, &write_fds, NULL, NULL)) <= 0) { | |
125 LOG(ERROR) << "Select error: " << safe_strerror(errno); | |
126 break; | |
127 } | |
128 // When a socket in the read set closes the connection, select() returns | |
129 // with that socket descriptor set as "ready to read". When we call | |
130 // TryRead() below, it will return false, but the while loop will continue | |
131 // to run until all the write operations are finished, to make sure the | |
132 // buffers are completely flushed out. | |
133 | |
134 // Keep running while we have some operation to do. | |
135 run = buffer1.TryRead(read_fds); | |
136 run = run || buffer2.TryRead(read_fds); | |
137 run = run || buffer1.TryWrite(write_fds); | |
138 run = run || buffer2.TryWrite(write_fds); | |
139 } | |
140 | |
141 delete this; | |
142 } | |
143 | |
144 void Forwarder::Join() { | |
145 NOTREACHED() << "Can't Join a Forwarder thread."; | |
146 } | |
147 | |
148 } // namespace forwarder | |
OLD | NEW |