Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: remoting/jingle_glue/chromium_socket_factory.cc

Issue 10783028: Implement ChromiumSocketFactory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "remoting/jingle_glue/chromium_socket_factory.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "jingle/glue/utils.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/ip_endpoint.h"
13 #include "net/base/net_errors.h"
14 #include "net/udp/udp_server_socket.h"
15 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
16
17 namespace remoting {
18
19 namespace {
20
21 // Size of the buffer to allocate for RecvFrom().
22 const int kReceiveBufferSize = 65536;
23
24 // Maximum amount of data in the send buffers. This is necessary to
Wez 2012/07/19 00:40:20 Your line-wrap seems to be at ten characters short
Sergey Ulanov 2012/07/19 20:16:39 Emacs wraps comments at 70 chars (by default and a
25 // prevent out-of-memory crashes if the caller sends data faster than
26 // Pepper's UDP API can handle it. This maximum should never be
27 // reached under normal conditions.
28 const int kMaxSendBufferSize = 256 * 1024;
29
30 class UdpPacketSocket : public talk_base::AsyncPacketSocket {
31 public:
32 explicit UdpPacketSocket();
Wez 2012/07/19 00:40:20 No need for explicit?
Sergey Ulanov 2012/07/19 20:16:39 Done.
33 virtual ~UdpPacketSocket();
34
35 // |min_port| and |max_port| are set to zero if the port number
36 // |should be assigned by the OS.
Wez 2012/07/19 00:40:20 typo: |should
Wez 2012/07/19 00:40:20 nit: Suggest "|min_port| and |max_port| limit the
Sergey Ulanov 2012/07/19 20:16:39 Done.
Sergey Ulanov 2012/07/19 20:16:39 Just removed this comment. meaning of these values
37 bool Init(const talk_base::SocketAddress& local_address,
Wez 2012/07/19 00:40:20 nit: Does local_address accept the usual INADDR_AN
Sergey Ulanov 2012/07/19 20:16:39 Yes, but it's never used that way.
38 int min_port, int max_port);
39
40 // talk_base::AsyncPacketSocket interface.
41 virtual talk_base::SocketAddress GetLocalAddress() const;
42 virtual talk_base::SocketAddress GetRemoteAddress() const;
43 virtual int Send(const void* data, size_t data_size);
44 virtual int SendTo(const void* data, size_t data_size,
45 const talk_base::SocketAddress& address);
46 virtual int Close();
47 virtual State GetState() const;
48 virtual int GetOption(talk_base::Socket::Option option, int* value);
49 virtual int SetOption(talk_base::Socket::Option option, int value);
50 virtual int GetError() const;
51 virtual void SetError(int error);
52
53 private:
54 struct PendingPacket {
55 PendingPacket(const void* buffer,
56 int buffer_size,
57 const net::IPEndPoint& address);
58
59 scoped_refptr<net::IOBufferWithSize> data;
60 net::IPEndPoint address;
61 };
62
63 void OnBindCompleted(int error);
64
65 void DoSend();
66 void OnSendCompleted(int result);
67
68 void DoRead();
69 void OnReadCompleted(int result);
70 void HandleReadResult(int result, bool* read_again);
71
72 scoped_ptr<net::UDPServerSocket> socket_;
73
74 State state_;
75 int error_;
76
77 talk_base::SocketAddress local_address_;
78
79 scoped_refptr<net::IOBuffer> receive_buffer_;
Wez 2012/07/19 00:40:20 nit: Add a comment explaining why we need these in
Sergey Ulanov 2012/07/19 20:16:39 Done.
80 net::IPEndPoint receive_address_;
81
82 bool send_pending_;
83 std::list<PendingPacket> send_queue_;
84 int send_queue_size_;
85
86 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
87 };
88
89 UdpPacketSocket::PendingPacket::PendingPacket(
90 const void* buffer,
91 int buffer_size,
92 const net::IPEndPoint& address)
93 : data(new net::IOBufferWithSize(buffer_size)),
94 address(address) {
95 memcpy(data->data(), buffer, buffer_size);
96 }
97
98 UdpPacketSocket::UdpPacketSocket()
99 : state_(STATE_CLOSED),
100 error_(0),
101 send_pending_(false),
102 send_queue_size_(0) {
103 }
104
105 UdpPacketSocket::~UdpPacketSocket() {
106 Close();
107 }
108
109 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address,
110 int min_port, int max_port) {
111 net::IPEndPoint local_endpoint;
112 if (!jingle_glue::SocketAddressToIPEndPoint(
113 local_address, &local_endpoint)) {
114 return false;
115 }
116
117 for (int port = min_port; port <= max_port; ++port) {
118 socket_.reset(new net::UDPServerSocket(NULL, net::NetLog::Source()));
119 net::IPEndPoint address_with_port(local_endpoint.address(), port);
Wez 2012/07/19 00:40:20 nit: endpoint_with_port
Sergey Ulanov 2012/07/19 20:16:39 removed this variable.
120 int result = socket_->Listen(address_with_port);
121 if (result == net::OK) {
122 break;
123 } else {
124 socket_.reset();
125 }
126 }
127
128 if (!socket_.get()) {
129 // Failed to bind the socket.
130 return false;
131 }
132
133 if (socket_->GetLocalAddress(&local_endpoint) != net::OK ||
134 !jingle_glue::IPEndPointToSocketAddress(local_endpoint,
135 &local_address_)) {
136 return false;
137 }
138
139 state_ = STATE_BOUND;
140 DoRead();
141
142 return true;
143 }
144
145 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const {
146 DCHECK_EQ(state_, STATE_BOUND);
147 return local_address_;
148 }
149
150 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
151 // UDP sockets are not connected - this method should never be called.
152 NOTREACHED();
153 return talk_base::SocketAddress();
154 }
155
156 int UdpPacketSocket::Send(const void* data, size_t data_size) {
157 // UDP sockets are not connected - this method should never be called.
158 NOTREACHED();
159 return EWOULDBLOCK;
160 }
161
162 int UdpPacketSocket::SendTo(const void* data, size_t data_size,
163 const talk_base::SocketAddress& address) {
164 if (state_ != STATE_BOUND) {
165 // TODO(sergeyu): StunPort may try to send stun request before we
166 // are bound. Fix that problem and change this to DCHECK.
Wez 2012/07/19 00:40:20 nit: OS socket APIs will typically return EINVAL r
Wez 2012/07/19 00:40:20 Doesn't that mean before Init() has been called? H
Sergey Ulanov 2012/07/19 20:16:39 I copied that TODO from PepperPacketSocketFactory,
167 return EINVAL;
168 }
169
170 if (error_ != 0) {
171 return error_;
172 }
173
174 net::IPEndPoint endpoint;
175 if (!jingle_glue::SocketAddressToIPEndPoint(address, &endpoint)) {
176 return EINVAL;
177 }
178
179 if (send_queue_size_ >= kMaxSendBufferSize) {
180 return EWOULDBLOCK;
181 }
182
183 send_queue_.push_back(PendingPacket(data, data_size, endpoint));
184 send_queue_size_ += data_size;
185 DoSend();
Wez 2012/07/19 00:40:20 nit: Blank line here, for consistency with Init()
Sergey Ulanov 2012/07/19 20:16:39 Done.
186 return data_size;
187 }
188
189 int UdpPacketSocket::Close() {
190 state_ = STATE_CLOSED;
191 socket_.reset();
192 return 0;
193 }
194
195 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
196 return state_;
197 }
198
199 int UdpPacketSocket::GetOption(talk_base::Socket::Option option, int* value) {
200 // This method is never called by libjingle.
201 NOTIMPLEMENTED();
202 return 0;
Wez 2012/07/19 00:40:20 nit: return -1; ?
Sergey Ulanov 2012/07/19 20:16:39 Done.
203 }
204
205 int UdpPacketSocket::SetOption(talk_base::Socket::Option option, int value) {
206 DCHECK(socket_.get());
Wez 2012/07/19 00:40:20 Shouldn't this be an EINVAL return akin to Send()?
Sergey Ulanov 2012/07/19 20:16:39 Done.
207 switch (option) {
208 case talk_base::Socket::OPT_DONTFRAGMENT:
209 NOTIMPLEMENTED();
210 return -1;
211
212 case talk_base::Socket::OPT_RCVBUF: {
213 bool success = socket_->SetReceiveBufferSize(value);
214 return success ? 0 : -1;
Wez 2012/07/19 00:40:20 nit: Should we SetError() in case of failure?
Sergey Ulanov 2012/07/19 20:16:39 PhysicalSocketServer doesn't do it.
215 }
216
217 case talk_base::Socket::OPT_SNDBUF: {
218 bool success = socket_->SetSendBufferSize(value);
219 return success ? 0 : -1;
220 }
221
222 case talk_base::Socket::OPT_NODELAY:
223 // OPT_NODELAY is only for TCP sockets.
224 NOTREACHED();
225 return -1;
226
227 case talk_base::Socket::OPT_IPV6_V6ONLY:
228 NOTIMPLEMENTED();
229 return -1;
230 }
231
232 NOTREACHED();
233 return -1;
234 }
235
236 int UdpPacketSocket::GetError() const {
237 return error_;
238 }
239
240 void UdpPacketSocket::SetError(int error) {
241 error_ = error;
242 }
243
244 void UdpPacketSocket::DoSend() {
245 if (send_pending_ || send_queue_.empty())
246 return;
247
248 int result = socket_->SendTo(
249 send_queue_.front().data, send_queue_.front().data->size(),
Wez 2012/07/19 00:40:20 nit: Ick. Pull out send_queue.front() as a local r
Sergey Ulanov 2012/07/19 20:16:39 Done.
250 send_queue_.front().address,
251 base::Bind(&UdpPacketSocket::OnSendCompleted,
252 base::Unretained(this)));
Wez 2012/07/19 00:40:20 off-topic: Whenever I see this it frightens me bec
Sergey Ulanov 2012/07/19 20:16:39 I agree.
253 if (result == net::ERR_IO_PENDING) {
254 send_pending_ = true;
255 } else {
256 OnSendCompleted(result);
257 }
258 }
259
260 void UdpPacketSocket::OnSendCompleted(int result) {
261 send_pending_ = false;
262
263 if (result < 0) {
264 // Treat all errors except ERR_ADDRESS_UNREACHABLE as fatal
265 // errors.
Wez 2012/07/19 00:40:20 nit: No need for the second use of "errors".
Sergey Ulanov 2012/07/19 20:16:39 Done.
266 if (result != net::ERR_ADDRESS_UNREACHABLE) {
267 LOG(ERROR) << "Send failed on a UDP socket: " << result;
268 error_ = EINVAL;
269 return;
270 }
271 }
272
273 send_queue_size_ -= send_queue_.front().data->size();
Wez 2012/07/19 00:40:20 nit: Clarify that we don't need to worry about par
Sergey Ulanov 2012/07/19 20:16:39 Done.
274 send_queue_.pop_front();
275 DoSend();
276 }
277
278 void UdpPacketSocket::DoRead() {
279 bool read_again = true;
280 while (read_again) {
281 receive_buffer_ = new net::IOBuffer(kReceiveBufferSize);
282 int result = socket_->RecvFrom(
283 receive_buffer_, kReceiveBufferSize, &receive_address_,
284 base::Bind(&UdpPacketSocket::OnReadCompleted, base::Unretained(this)));
285 HandleReadResult(result, &read_again);
Wez 2012/07/19 00:40:20 It seems cleaner to check whether result > 0 after
Sergey Ulanov 2012/07/19 20:16:39 Done.
286 }
287 }
288
289 void UdpPacketSocket::OnReadCompleted(int result) {
290 bool read_again;
291 HandleReadResult(result, &read_again);
292 if (read_again) {
293 DoRead();
294 }
295 }
296
297 void UdpPacketSocket::HandleReadResult(int result, bool* read_again) {
Wez 2012/07/19 00:40:20 Why not have read_again be the return value of Han
Sergey Ulanov 2012/07/19 20:16:39 It's more readable with the parameter instead of r
298 if (result == net::ERR_IO_PENDING) {
299 *read_again = false;
300 return;
301 }
302
303 if (result > 0) {
304 talk_base::SocketAddress address;
305 if (!jingle_glue::IPEndPointToSocketAddress(receive_address_, &address)) {
306 LOG(ERROR) << "Failed to covert address received from RecvFrom().";
Wez 2012/07/19 00:40:20 I think you want to read again even if the peer ad
Wez 2012/07/19 00:40:20 typo: covert
Sergey Ulanov 2012/07/19 20:16:39 Done.
Sergey Ulanov 2012/07/19 20:16:39 Done.
307 return;
308 }
309 SignalReadPacket(this, receive_buffer_->data(), result, address);
310 *read_again = true;
311 } else {
312 LOG(ERROR) << "Received error when reading from UDP socket: " << result;
313 *read_again = false;
314 }
315 }
316
317 } // namespace
318
319 ChromiumPacketSocketFactory::ChromiumPacketSocketFactory() {
320 }
321
322 ChromiumPacketSocketFactory::~ChromiumPacketSocketFactory() {
323 }
324
325 talk_base::AsyncPacketSocket* ChromiumPacketSocketFactory::CreateUdpSocket(
326 const talk_base::SocketAddress& local_address,
327 int min_port, int max_port) {
328 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket());
329 if (!result->Init(local_address, min_port, max_port))
330 return NULL;
331 return result.release();
332 }
333
334 talk_base::AsyncPacketSocket*
335 ChromiumPacketSocketFactory::CreateServerTcpSocket(
336 const talk_base::SocketAddress& local_address,
337 int min_port, int max_port,
338 bool ssl) {
339 // We don't use TCP sockets for remoting connections.
340 NOTREACHED();
341 return NULL;
342 }
343
344 talk_base::AsyncPacketSocket*
345 ChromiumPacketSocketFactory::CreateClientTcpSocket(
346 const talk_base::SocketAddress& local_address,
347 const talk_base::SocketAddress& remote_address,
348 const talk_base::ProxyInfo& proxy_info,
349 const std::string& user_agent,
350 bool ssl) {
351 // We don't use TCP sockets for remoting connections.
352 NOTREACHED();
353 return NULL;
354 }
355
356 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698