Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / mojo / services / network / udp_socket_impl.cc
blobcc11da7c0e89fdd50f5485b4b808677da30e063f
1 // Copyright 2014 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 "mojo/services/network/udp_socket_impl.h"
7 #include <string.h>
9 #include <algorithm>
10 #include <limits>
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/stl_util.h"
15 #include "mojo/services/network/net_adapters.h"
16 #include "mojo/services/network/net_address_type_converters.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/rand_callback.h"
20 #include "net/udp/datagram_socket.h"
22 namespace mojo {
24 namespace {
26 const int kMaxReadSize = 128 * 1024;
27 const size_t kMaxWriteSize = 128 * 1024;
28 const size_t kMaxPendingSendRequestsUpperbound = 128;
29 const size_t kDefaultMaxPendingSendRequests = 32;
31 } // namespace
33 UDPSocketImpl::PendingSendRequest::PendingSendRequest() {}
35 UDPSocketImpl::PendingSendRequest::~PendingSendRequest() {}
37 UDPSocketImpl::UDPSocketImpl(InterfaceRequest<UDPSocket> request)
38 : binding_(this, request.Pass()),
39 socket_(net::DatagramSocket::DEFAULT_BIND,
40 net::RandIntCallback(),
41 nullptr,
42 net::NetLog::Source()),
43 state_(NOT_BOUND_OR_CONNECTED),
44 allow_address_reuse_(false),
45 remaining_recv_slots_(0),
46 max_pending_send_requests_(kDefaultMaxPendingSendRequests) {
49 UDPSocketImpl::~UDPSocketImpl() {
50 STLDeleteElements(&pending_send_requests_);
53 void UDPSocketImpl::AllowAddressReuse(
54 const Callback<void(NetworkErrorPtr)>& callback) {
55 if (IsBoundOrConnected()) {
56 callback.Run(MakeNetworkError(net::ERR_FAILED));
57 return;
60 allow_address_reuse_ = true;
61 callback.Run(MakeNetworkError(net::OK));
64 void UDPSocketImpl::Bind(
65 NetAddressPtr addr,
66 const Callback<void(NetworkErrorPtr,
67 NetAddressPtr,
68 InterfaceRequest<UDPSocketReceiver>)>& callback) {
69 int net_result = net::OK;
70 bool opened = false;
72 do {
73 if (IsBoundOrConnected()) {
74 net_result = net::ERR_FAILED;
75 break;
78 net::IPEndPoint ip_end_point = addr.To<net::IPEndPoint>();
79 if (ip_end_point.GetFamily() == net::ADDRESS_FAMILY_UNSPECIFIED) {
80 net_result = net::ERR_ADDRESS_INVALID;
81 break;
84 net_result = socket_.Open(ip_end_point.GetFamily());
85 if (net_result != net::OK)
86 break;
87 opened = true;
89 if (allow_address_reuse_) {
90 net_result = socket_.AllowAddressReuse();
91 if (net_result != net::OK)
92 break;
95 net_result = socket_.Bind(ip_end_point);
96 if (net_result != net::OK)
97 break;
99 net::IPEndPoint bound_ip_end_point;
100 net_result = socket_.GetLocalAddress(&bound_ip_end_point);
101 if (net_result != net::OK)
102 break;
104 state_ = BOUND;
105 callback.Run(MakeNetworkError(net_result),
106 NetAddress::From(bound_ip_end_point), GetProxy(&receiver_));
108 if (remaining_recv_slots_ > 0) {
109 DCHECK(!recvfrom_buffer_.get());
110 DoRecvFrom();
112 return;
113 } while (false);
115 DCHECK(net_result != net::OK);
116 if (opened)
117 socket_.Close();
118 callback.Run(MakeNetworkError(net_result), nullptr, nullptr);
121 void UDPSocketImpl::Connect(
122 NetAddressPtr remote_addr,
123 const Callback<void(NetworkErrorPtr,
124 NetAddressPtr,
125 InterfaceRequest<UDPSocketReceiver>)>& callback) {
126 int net_result = net::OK;
127 bool opened = false;
129 do {
130 if (IsBoundOrConnected()) {
131 net_result = net::ERR_FAILED;
132 break;
135 net::IPEndPoint ip_end_point = remote_addr.To<net::IPEndPoint>();
136 if (ip_end_point.GetFamily() == net::ADDRESS_FAMILY_UNSPECIFIED) {
137 net_result = net::ERR_ADDRESS_INVALID;
138 break;
141 net_result = socket_.Open(ip_end_point.GetFamily());
142 if (net_result != net::OK)
143 break;
144 opened = true;
146 net_result = socket_.Connect(ip_end_point);
147 if (net_result != net::OK)
148 break;
150 net::IPEndPoint local_ip_end_point;
151 net_result = socket_.GetLocalAddress(&local_ip_end_point);
152 if (net_result != net::OK)
153 break;
155 state_ = CONNECTED;
156 callback.Run(MakeNetworkError(net_result),
157 NetAddress::From(local_ip_end_point), GetProxy(&receiver_));
159 if (remaining_recv_slots_ > 0) {
160 DCHECK(!recvfrom_buffer_.get());
161 DoRecvFrom();
163 return;
164 } while (false);
166 DCHECK(net_result != net::OK);
167 if (opened)
168 socket_.Close();
169 callback.Run(MakeNetworkError(net_result), nullptr, nullptr);
172 void UDPSocketImpl::SetSendBufferSize(
173 uint32_t size,
174 const Callback<void(NetworkErrorPtr)>& callback) {
175 if (!IsBoundOrConnected()) {
176 callback.Run(MakeNetworkError(net::ERR_FAILED));
177 return;
180 if (size > static_cast<uint32_t>(std::numeric_limits<int32_t>::max()))
181 size = std::numeric_limits<int32_t>::max();
183 int net_result = socket_.SetSendBufferSize(static_cast<int32_t>(size));
184 callback.Run(MakeNetworkError(net_result));
187 void UDPSocketImpl::SetReceiveBufferSize(
188 uint32_t size,
189 const Callback<void(NetworkErrorPtr)>& callback) {
190 if (!IsBoundOrConnected()) {
191 callback.Run(MakeNetworkError(net::ERR_FAILED));
192 return;
195 if (size > static_cast<uint32_t>(std::numeric_limits<int32_t>::max()))
196 size = std::numeric_limits<int32_t>::max();
198 int net_result = socket_.SetReceiveBufferSize(static_cast<int32_t>(size));
199 callback.Run(MakeNetworkError(net_result));
202 void UDPSocketImpl::NegotiateMaxPendingSendRequests(
203 uint32_t requested_size,
204 const Callback<void(uint32_t)>& callback) {
205 if (requested_size != 0) {
206 max_pending_send_requests_ =
207 std::min(kMaxPendingSendRequestsUpperbound,
208 static_cast<size_t>(requested_size));
210 callback.Run(static_cast<uint32_t>(max_pending_send_requests_));
212 if (pending_send_requests_.size() > max_pending_send_requests_) {
213 std::deque<PendingSendRequest*> discarded_requests(
214 pending_send_requests_.begin() + max_pending_send_requests_,
215 pending_send_requests_.end());
216 pending_send_requests_.resize(max_pending_send_requests_);
217 for (auto& discarded_request : discarded_requests) {
218 discarded_request->callback.Run(
219 MakeNetworkError(net::ERR_INSUFFICIENT_RESOURCES));
220 delete discarded_request;
225 void UDPSocketImpl::ReceiveMore(uint32_t datagram_number) {
226 if (!receiver_)
227 return;
228 if (datagram_number == 0)
229 return;
230 if (std::numeric_limits<size_t>::max() - remaining_recv_slots_ <
231 datagram_number) {
232 return;
235 remaining_recv_slots_ += datagram_number;
237 if (IsBoundOrConnected() && !recvfrom_buffer_.get()) {
238 DCHECK_EQ(datagram_number, remaining_recv_slots_);
239 DoRecvFrom();
243 void UDPSocketImpl::SendTo(NetAddressPtr dest_addr,
244 Array<uint8_t> data,
245 const Callback<void(NetworkErrorPtr)>& callback) {
246 if (!IsBoundOrConnected()) {
247 callback.Run(MakeNetworkError(net::ERR_FAILED));
248 return;
250 if (state_ == BOUND && !dest_addr) {
251 callback.Run(MakeNetworkError(net::ERR_INVALID_ARGUMENT));
252 return;
255 if (sendto_buffer_.get()) {
256 if (pending_send_requests_.size() >= max_pending_send_requests_) {
257 callback.Run(MakeNetworkError(net::ERR_INSUFFICIENT_RESOURCES));
258 return;
261 PendingSendRequest* request = new PendingSendRequest;
262 request->addr = dest_addr.Pass();
263 request->data = data.Pass();
264 request->callback = callback;
265 pending_send_requests_.push_back(request);
266 return;
269 DCHECK_EQ(0u, pending_send_requests_.size());
271 DoSendTo(dest_addr.Pass(), data.Pass(), callback);
274 void UDPSocketImpl::DoRecvFrom() {
275 DCHECK(IsBoundOrConnected());
276 DCHECK(receiver_);
277 DCHECK(!recvfrom_buffer_.get());
278 DCHECK_GT(remaining_recv_slots_, 0u);
280 recvfrom_buffer_ = new net::IOBuffer(kMaxReadSize);
282 // It is safe to use base::Unretained(this) because |socket_| is owned by this
283 // object. If this object gets destroyed (and so does |socket_|), the callback
284 // won't be called.
285 int net_result = socket_.RecvFrom(
286 recvfrom_buffer_.get(),
287 kMaxReadSize,
288 state_ == BOUND ? &recvfrom_address_ : nullptr,
289 base::Bind(&UDPSocketImpl::OnRecvFromCompleted, base::Unretained(this)));
290 if (net_result != net::ERR_IO_PENDING)
291 OnRecvFromCompleted(net_result);
294 void UDPSocketImpl::DoSendTo(NetAddressPtr addr,
295 Array<uint8_t> data,
296 const Callback<void(NetworkErrorPtr)>& callback) {
297 DCHECK(IsBoundOrConnected());
298 DCHECK(!sendto_buffer_.get());
300 if (data.size() > kMaxWriteSize) {
301 callback.Run(MakeNetworkError(net::ERR_INVALID_ARGUMENT));
302 return;
304 sendto_buffer_ = new net::IOBufferWithSize(static_cast<int>(data.size()));
305 if (data.size() > 0)
306 memcpy(sendto_buffer_->data(), &data.storage()[0], data.size());
308 int net_result = net::OK;
309 if (addr) {
310 net::IPEndPoint ip_end_point = addr.To<net::IPEndPoint>();
311 if (ip_end_point.GetFamily() == net::ADDRESS_FAMILY_UNSPECIFIED) {
312 callback.Run(MakeNetworkError(net::ERR_ADDRESS_INVALID));
313 return;
316 // It is safe to use base::Unretained(this) because |socket_| is owned by
317 // this object. If this object gets destroyed (and so does |socket_|), the
318 // callback won't be called.
319 net_result = socket_.SendTo(sendto_buffer_.get(), sendto_buffer_->size(),
320 ip_end_point,
321 base::Bind(&UDPSocketImpl::OnSendToCompleted,
322 base::Unretained(this), callback));
323 } else {
324 DCHECK(state_ == CONNECTED);
325 net_result = socket_.Write(sendto_buffer_.get(), sendto_buffer_->size(),
326 base::Bind(&UDPSocketImpl::OnSendToCompleted,
327 base::Unretained(this), callback));
329 if (net_result != net::ERR_IO_PENDING)
330 OnSendToCompleted(callback, net_result);
333 void UDPSocketImpl::OnRecvFromCompleted(int net_result) {
334 DCHECK(recvfrom_buffer_.get());
336 NetAddressPtr net_address;
337 Array<uint8_t> array;
338 if (net_result >= 0) {
339 if (state_ == BOUND)
340 net_address = NetAddress::From(recvfrom_address_);
342 std::vector<uint8_t> data(net_result);
343 if (net_result > 0)
344 memcpy(&data[0], recvfrom_buffer_->data(), net_result);
346 array.Swap(&data);
348 recvfrom_buffer_ = nullptr;
350 receiver_->OnReceived(MakeNetworkError(net_result), net_address.Pass(),
351 array.Pass());
352 DCHECK_GT(remaining_recv_slots_, 0u);
353 remaining_recv_slots_--;
354 if (remaining_recv_slots_ > 0)
355 DoRecvFrom();
358 void UDPSocketImpl::OnSendToCompleted(
359 const Callback<void(NetworkErrorPtr)>& callback,
360 int net_result) {
361 DCHECK(sendto_buffer_.get());
363 sendto_buffer_ = nullptr;
365 callback.Run(MakeNetworkError(net_result));
367 if (pending_send_requests_.empty())
368 return;
370 scoped_ptr<PendingSendRequest> request(pending_send_requests_.front());
371 pending_send_requests_.pop_front();
373 DoSendTo(request->addr.Pass(), request->data.Pass(), request->callback);
376 } // namespace mojo