Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / socket / udp_socket.cc
blob47eae2d735153c7641061c85022e4df53d9828db
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 "extensions/browser/api/socket/udp_socket.h"
7 #include <algorithm>
9 #include "base/lazy_instance.h"
10 #include "extensions/browser/api/api_resource.h"
11 #include "net/base/ip_endpoint.h"
12 #include "net/base/net_errors.h"
13 #include "net/udp/datagram_socket.h"
14 #include "net/udp/udp_client_socket.h"
16 namespace extensions {
18 static base::LazyInstance<
19 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> > >
20 g_factory = LAZY_INSTANCE_INITIALIZER;
22 // static
23 template <>
24 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> >*
25 ApiResourceManager<ResumableUDPSocket>::GetFactoryInstance() {
26 return g_factory.Pointer();
29 UDPSocket::UDPSocket(const std::string& owner_extension_id)
30 : Socket(owner_extension_id),
31 socket_(net::DatagramSocket::DEFAULT_BIND,
32 net::RandIntCallback(),
33 NULL,
34 net::NetLog::Source()) {}
36 UDPSocket::~UDPSocket() { Disconnect(); }
38 void UDPSocket::Connect(const net::AddressList& address,
39 const CompletionCallback& callback) {
40 int result = net::ERR_CONNECTION_FAILED;
41 do {
42 if (is_connected_)
43 break;
45 // UDP API only connects to the first address received from DNS so
46 // connection may not work even if other addresses are reachable.
47 net::IPEndPoint ip_end_point = address.front();
48 result = socket_.Open(ip_end_point.GetFamily());
49 if (result != net::OK)
50 break;
52 result = socket_.Connect(ip_end_point);
53 if (result != net::OK) {
54 socket_.Close();
55 break;
57 is_connected_ = true;
58 } while (false);
60 callback.Run(result);
63 int UDPSocket::Bind(const std::string& address, uint16 port) {
64 if (IsBound())
65 return net::ERR_CONNECTION_FAILED;
67 net::IPEndPoint ip_end_point;
68 if (!StringAndPortToIPEndPoint(address, port, &ip_end_point))
69 return net::ERR_INVALID_ARGUMENT;
71 int result = socket_.Open(ip_end_point.GetFamily());
72 if (result != net::OK)
73 return result;
75 result = socket_.Bind(ip_end_point);
76 if (result != net::OK)
77 socket_.Close();
78 return result;
81 void UDPSocket::Disconnect() {
82 is_connected_ = false;
83 socket_.Close();
84 read_callback_.Reset();
85 recv_from_callback_.Reset();
86 send_to_callback_.Reset();
87 multicast_groups_.clear();
90 void UDPSocket::Read(int count, const ReadCompletionCallback& callback) {
91 DCHECK(!callback.is_null());
93 if (!read_callback_.is_null()) {
94 callback.Run(net::ERR_IO_PENDING, NULL);
95 return;
96 } else {
97 read_callback_ = callback;
100 int result = net::ERR_FAILED;
101 scoped_refptr<net::IOBuffer> io_buffer;
102 do {
103 if (count < 0) {
104 result = net::ERR_INVALID_ARGUMENT;
105 break;
108 if (!socket_.is_connected()) {
109 result = net::ERR_SOCKET_NOT_CONNECTED;
110 break;
113 io_buffer = new net::IOBuffer(count);
114 result = socket_.Read(
115 io_buffer.get(),
116 count,
117 base::Bind(
118 &UDPSocket::OnReadComplete, base::Unretained(this), io_buffer));
119 } while (false);
121 if (result != net::ERR_IO_PENDING)
122 OnReadComplete(io_buffer, result);
125 int UDPSocket::WriteImpl(net::IOBuffer* io_buffer,
126 int io_buffer_size,
127 const net::CompletionCallback& callback) {
128 if (!socket_.is_connected())
129 return net::ERR_SOCKET_NOT_CONNECTED;
130 else
131 return socket_.Write(io_buffer, io_buffer_size, callback);
134 void UDPSocket::RecvFrom(int count,
135 const RecvFromCompletionCallback& callback) {
136 DCHECK(!callback.is_null());
138 if (!recv_from_callback_.is_null()) {
139 callback.Run(net::ERR_IO_PENDING, NULL, std::string(), 0);
140 return;
141 } else {
142 recv_from_callback_ = callback;
145 int result = net::ERR_FAILED;
146 scoped_refptr<net::IOBuffer> io_buffer;
147 scoped_refptr<IPEndPoint> address;
148 do {
149 if (count < 0) {
150 result = net::ERR_INVALID_ARGUMENT;
151 break;
154 if (!socket_.is_connected()) {
155 result = net::ERR_SOCKET_NOT_CONNECTED;
156 break;
159 io_buffer = new net::IOBuffer(count);
160 address = new IPEndPoint();
161 result = socket_.RecvFrom(io_buffer.get(),
162 count,
163 &address->data,
164 base::Bind(&UDPSocket::OnRecvFromComplete,
165 base::Unretained(this),
166 io_buffer,
167 address));
168 } while (false);
170 if (result != net::ERR_IO_PENDING)
171 OnRecvFromComplete(io_buffer, address, result);
174 void UDPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer,
175 int byte_count,
176 const net::IPEndPoint& address,
177 const CompletionCallback& callback) {
178 DCHECK(!callback.is_null());
180 if (!send_to_callback_.is_null()) {
181 // TODO(penghuang): Put requests in a pending queue to support multiple
182 // sendTo calls.
183 callback.Run(net::ERR_IO_PENDING);
184 return;
185 } else {
186 send_to_callback_ = callback;
189 int result = net::ERR_FAILED;
190 do {
191 if (!socket_.is_connected()) {
192 result = net::ERR_SOCKET_NOT_CONNECTED;
193 break;
196 result = socket_.SendTo(
197 io_buffer.get(), byte_count, address,
198 base::Bind(&UDPSocket::OnSendToComplete, base::Unretained(this)));
199 } while (false);
201 if (result != net::ERR_IO_PENDING)
202 OnSendToComplete(result);
205 bool UDPSocket::IsConnected() { return is_connected_; }
207 bool UDPSocket::GetPeerAddress(net::IPEndPoint* address) {
208 return !socket_.GetPeerAddress(address);
211 bool UDPSocket::GetLocalAddress(net::IPEndPoint* address) {
212 return !socket_.GetLocalAddress(address);
215 Socket::SocketType UDPSocket::GetSocketType() const { return Socket::TYPE_UDP; }
217 void UDPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
218 int result) {
219 DCHECK(!read_callback_.is_null());
220 read_callback_.Run(result, io_buffer);
221 read_callback_.Reset();
224 void UDPSocket::OnRecvFromComplete(scoped_refptr<net::IOBuffer> io_buffer,
225 scoped_refptr<IPEndPoint> address,
226 int result) {
227 DCHECK(!recv_from_callback_.is_null());
228 std::string ip;
229 uint16 port = 0;
230 if (result > 0 && address.get()) {
231 IPEndPointToStringAndPort(address->data, &ip, &port);
233 recv_from_callback_.Run(result, io_buffer, ip, port);
234 recv_from_callback_.Reset();
237 void UDPSocket::OnSendToComplete(int result) {
238 DCHECK(!send_to_callback_.is_null());
239 send_to_callback_.Run(result);
240 send_to_callback_.Reset();
243 bool UDPSocket::IsBound() { return socket_.is_connected(); }
245 int UDPSocket::JoinGroup(const std::string& address) {
246 net::IPAddressNumber ip;
247 if (!net::ParseIPLiteralToNumber(address, &ip))
248 return net::ERR_ADDRESS_INVALID;
250 std::string normalized_address = net::IPAddressToString(ip);
251 std::vector<std::string>::iterator find_result = std::find(
252 multicast_groups_.begin(), multicast_groups_.end(), normalized_address);
253 if (find_result != multicast_groups_.end())
254 return net::ERR_ADDRESS_INVALID;
256 int rv = socket_.JoinGroup(ip);
257 if (rv == 0)
258 multicast_groups_.push_back(normalized_address);
259 return rv;
262 int UDPSocket::LeaveGroup(const std::string& address) {
263 net::IPAddressNumber ip;
264 if (!net::ParseIPLiteralToNumber(address, &ip))
265 return net::ERR_ADDRESS_INVALID;
267 std::string normalized_address = net::IPAddressToString(ip);
268 std::vector<std::string>::iterator find_result = std::find(
269 multicast_groups_.begin(), multicast_groups_.end(), normalized_address);
270 if (find_result == multicast_groups_.end())
271 return net::ERR_ADDRESS_INVALID;
273 int rv = socket_.LeaveGroup(ip);
274 if (rv == 0)
275 multicast_groups_.erase(find_result);
276 return rv;
279 int UDPSocket::SetMulticastTimeToLive(int ttl) {
280 return socket_.SetMulticastTimeToLive(ttl);
283 int UDPSocket::SetMulticastLoopbackMode(bool loopback) {
284 return socket_.SetMulticastLoopbackMode(loopback);
287 int UDPSocket::SetBroadcast(bool enabled) {
288 if (!socket_.is_connected()) {
289 return net::ERR_SOCKET_NOT_CONNECTED;
291 return socket_.SetBroadcast(enabled);
294 const std::vector<std::string>& UDPSocket::GetJoinedGroups() const {
295 return multicast_groups_;
298 ResumableUDPSocket::ResumableUDPSocket(const std::string& owner_extension_id)
299 : UDPSocket(owner_extension_id),
300 persistent_(false),
301 buffer_size_(0),
302 paused_(false) {}
304 bool ResumableUDPSocket::IsPersistent() const { return persistent(); }
306 } // namespace extensions