Chromium Code Reviews

Side by Side Diff: mojo/services/network/udp_socket_impl.cc

Issue 596383002: Mojo UDP API implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@udp_interface
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
(Empty)
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.
4
5 #include "mojo/services/network/udp_socket_impl.h"
6
7 #include <string.h>
8
9 #include <limits>
10
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "mojo/services/network/net_address_type_converters.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16
17 namespace mojo {
18
19 namespace {
20
21 const int kMaxReadSize = 128 * 1024;
22 const size_t kMaxPendingSendRequests = 32;
23
24 NetworkErrorPtr MakeNetworkError(int error_code) {
25 NetworkErrorPtr error(NetworkError::New());
26 error->code = error_code;
27 if (error_code <= 0)
28 error->description = net::ErrorToString(error_code);
29 return error.Pass();
30 }
31
32 } // namespace
33
34 UDPSocketImpl::PendingSendRequest::PendingSendRequest() {}
35
36 UDPSocketImpl::PendingSendRequest::~PendingSendRequest() {}
37
38 UDPSocketImpl::UDPSocketImpl() : socket_(NULL, net::NetLog::Source()),
39 bound_(false),
40 remaining_recv_slots_(0) {
41 }
42
43 UDPSocketImpl::~UDPSocketImpl() {
44 while (!pending_send_requests_.empty()) {
45 delete pending_send_requests_.front();
46 pending_send_requests_.pop();
47 }
48 }
49
50 void UDPSocketImpl::SetSendBufferSize(
51 uint32_t size,
52 const Callback<void(NetworkErrorPtr)>& callback) {
53 if (!bound_) {
54 callback.Run(MakeNetworkError(net::ERR_FAILED));
55 return;
56 }
57
58 if (size > static_cast<uint32_t>(std::numeric_limits<int32>::max()))
brettw 2014/09/29 18:24:25 I think we're recommending int32_t for new code. S
yzshen1 2014/09/29 21:51:12 I think you mean "changing int32 to int32_t" inste
59 size = std::numeric_limits<int32>::max();
60
61 int net_result = socket_.SetSendBufferSize(static_cast<int32>(size));
62 callback.Run(MakeNetworkError(net_result));
63 }
64
65 void UDPSocketImpl::SetReceiveBufferSize(
66 uint32_t size,
67 const Callback<void(NetworkErrorPtr)>& callback) {
68 if (!bound_) {
69 callback.Run(MakeNetworkError(net::ERR_FAILED));
70 return;
71 }
72
73 if (size > static_cast<uint32_t>(std::numeric_limits<int32>::max()))
74 size = std::numeric_limits<int32>::max();
75
76 int net_result = socket_.SetReceiveBufferSize(static_cast<int32>(size));
77 callback.Run(MakeNetworkError(net_result));
78 }
79
80 void UDPSocketImpl::AllowAddressReuse(
81 const Callback<void(NetworkErrorPtr)>& callback) {
82 if (bound_) {
83 callback.Run(MakeNetworkError(net::ERR_FAILED));
84 return;
85 }
86
87 socket_.AllowAddressReuse();
88 callback.Run(MakeNetworkError(net::OK));
89 }
90
91 void UDPSocketImpl::Bind(
92 NetAddressPtr addr,
93 const Callback<void(NetworkErrorPtr, NetAddressPtr)>& callback) {
94 if (bound_) {
95 callback.Run(MakeNetworkError(net::ERR_FAILED), NetAddressPtr());
96 return;
97 }
98
99 net::IPEndPoint ip_end_point = addr.To<net::IPEndPoint>();
100 if (ip_end_point.GetFamily() == net::ADDRESS_FAMILY_UNSPECIFIED) {
101 callback.Run(MakeNetworkError(net::ERR_ADDRESS_INVALID), NetAddressPtr());
102 return;
103 }
104
105 int net_result = socket_.Listen(ip_end_point);
106 if (net_result != net::OK) {
107 callback.Run(MakeNetworkError(net_result), NetAddressPtr());
108 return;
109 }
110
111 net::IPEndPoint bound_ip_end_point;
112 NetAddressPtr bound_addr;
113 net_result = socket_.GetLocalAddress(&bound_ip_end_point);
114 if (net_result == net::OK)
115 bound_addr = NetAddress::From(bound_ip_end_point);
116
117 bound_ = true;
118 callback.Run(MakeNetworkError(net::OK), bound_addr.Pass());
119 }
120
121 void UDPSocketImpl::ReceiveMorePackets(uint32_t number) {
122 if (!bound_ || number == 0)
123 return;
124 if (std::numeric_limits<size_t>::max() - remaining_recv_slots_ < number)
125 return;
126
127 remaining_recv_slots_ += number;
128
129 if (!recvfrom_buffer_.get()) {
130 DCHECK_EQ(number, remaining_recv_slots_);
131 DoRecvFrom();
132 }
133 }
134
135 void UDPSocketImpl::SendToAndForget(NetAddressPtr addr, Array<uint8_t> data) {
136 SendTo(addr.Pass(), data.Pass(), Callback<void(NetworkErrorPtr)>());
137 }
138
139 void UDPSocketImpl::SendTo(NetAddressPtr addr,
140 Array<uint8_t> data,
141 const Callback<void(NetworkErrorPtr)>& callback) {
142 if (!bound_) {
143 callback.Run(MakeNetworkError(net::ERR_FAILED));
144 return;
145 }
146
147 if (sendto_buffer_.get()) {
148 if (pending_send_requests_.size() >= kMaxPendingSendRequests) {
brettw 2014/09/29 18:24:25 It's not clear to me from the .mojom that there wo
yzshen1 2014/09/29 21:51:11 Done. Comments added.
149 callback.Run(MakeNetworkError(net::ERR_INSUFFICIENT_RESOURCES));
150 return;
151 }
152
153 PendingSendRequest* request = new PendingSendRequest;
154 request->addr = addr.Pass();
155 request->data = data.Pass();
156 request->callback = callback;
157 pending_send_requests_.push(request);
158 return;
159 }
160
161 DCHECK_EQ(0u, pending_send_requests_.size());
162
163 DoSendTo(addr.Pass(), data.Pass(), callback);
164 }
165
166 void UDPSocketImpl::DoRecvFrom() {
167 DCHECK(bound_);
168 DCHECK(!recvfrom_buffer_.get());
169 DCHECK_GT(remaining_recv_slots_, 0u);
170
171 recvfrom_buffer_ = new net::IOBuffer(kMaxReadSize);
172
173 // It is safe to use base::Unretained(this) because |socket_| is owned by this
174 // object. If this object gets destroyed (and so does |socket_|), the callback
175 // won't be called.
176 int net_result = socket_.RecvFrom(
177 recvfrom_buffer_.get(),
178 kMaxReadSize,
179 &recvfrom_address_,
180 base::Bind(&UDPSocketImpl::OnRecvFromCompleted, base::Unretained(this)));
181 if (net_result != net::ERR_IO_PENDING)
182 OnRecvFromCompleted(net_result);
183 }
184
185 void UDPSocketImpl::DoSendTo(NetAddressPtr addr,
186 Array<uint8_t> data,
187 const Callback<void(NetworkErrorPtr)>& callback) {
188 DCHECK(bound_);
189 DCHECK(!sendto_buffer_.get());
190
191 net::IPEndPoint ip_end_point = addr.To<net::IPEndPoint>();
192 if (ip_end_point.GetFamily() == net::ADDRESS_FAMILY_UNSPECIFIED) {
193 callback.Run(MakeNetworkError(net::ERR_ADDRESS_INVALID));
194 return;
195 }
196
197 sendto_buffer_ = new net::IOBufferWithSize(data.size());
198 if (data.size() > 0)
199 memcpy(sendto_buffer_->data(), &data.storage()[0], data.size());
200
201 // It is safe to use base::Unretained(this) because |socket_| is owned by this
202 // object. If this object gets destroyed (and so does |socket_|), the callback
203 // won't be called.
204 int net_result = socket_.SendTo(sendto_buffer_.get(), sendto_buffer_->size(),
205 ip_end_point,
206 base::Bind(&UDPSocketImpl::OnSendToCompleted,
207 base::Unretained(this), callback));
208 if (net_result != net::ERR_IO_PENDING)
209 OnSendToCompleted(callback, net_result);
210 }
211
212 void UDPSocketImpl::OnRecvFromCompleted(int net_result) {
213 DCHECK(recvfrom_buffer_.get());
214
215 NetAddressPtr net_address;
216 Array<uint8_t> array;
217 if (net_result >= 0) {
218 net_address = NetAddress::From(recvfrom_address_);
219 std::vector<uint8_t> data(net_result);
220 if (net_result > 0)
221 memcpy(&data[0], recvfrom_buffer_->data(), net_result);
222
223 array.Swap(&data);
224 }
225 recvfrom_buffer_ = NULL;
226
227 client()->OnReceived(MakeNetworkError(net_result), net_address.Pass(),
228 array.Pass());
229
230 DCHECK_GT(remaining_recv_slots_, 0u);
231 remaining_recv_slots_--;
232 if (remaining_recv_slots_ > 0)
233 DoRecvFrom();
234 }
235
236 void UDPSocketImpl::OnSendToCompleted(
237 const Callback<void(NetworkErrorPtr)>& callback,
238 int net_result) {
239 DCHECK(sendto_buffer_.get());
240
241 sendto_buffer_ = NULL;
242
243 callback.Run(MakeNetworkError(net_result));
244
245 if (pending_send_requests_.empty())
246 return;
247
248 scoped_ptr<PendingSendRequest> request(pending_send_requests_.front());
249 pending_send_requests_.pop();
250
251 DoSendTo(request->addr.Pass(), request->data.Pass(), request->callback);
252 }
253
254 } // namespace mojo
OLDNEW

Powered by Google App Engine