Update path of checkdeps to buildtools checkout
[chromium-blink-merge.git] / extensions / browser / api / socket / udp_socket.cc
blob8e3650003abd569348af0afb0baaf21660ec4ca6
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 "extensions/browser/api/api_resource.h"
10 #include "net/base/ip_endpoint.h"
11 #include "net/base/net_errors.h"
12 #include "net/udp/datagram_socket.h"
13 #include "net/udp/udp_client_socket.h"
15 namespace extensions {
17 static base::LazyInstance<
18 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> > >
19 g_factory = LAZY_INSTANCE_INITIALIZER;
21 // static
22 template <>
23 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> >*
24 ApiResourceManager<ResumableUDPSocket>::GetFactoryInstance() {
25 return g_factory.Pointer();
28 UDPSocket::UDPSocket(const std::string& owner_extension_id)
29 : Socket(owner_extension_id),
30 socket_(net::DatagramSocket::DEFAULT_BIND,
31 net::RandIntCallback(),
32 NULL,
33 net::NetLog::Source()) {}
35 UDPSocket::~UDPSocket() { Disconnect(); }
37 void UDPSocket::Connect(const std::string& address,
38 int port,
39 const CompletionCallback& callback) {
40 int result = net::ERR_CONNECTION_FAILED;
41 do {
42 if (is_connected_)
43 break;
45 net::IPEndPoint ip_end_point;
46 if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) {
47 result = net::ERR_ADDRESS_INVALID;
48 break;
51 result = socket_.Connect(ip_end_point);
52 is_connected_ = (result == net::OK);
53 } while (false);
55 callback.Run(result);
58 int UDPSocket::Bind(const std::string& address, int port) {
59 if (IsBound())
60 return net::ERR_CONNECTION_FAILED;
62 net::IPEndPoint ip_end_point;
63 if (!StringAndPortToIPEndPoint(address, port, &ip_end_point))
64 return net::ERR_INVALID_ARGUMENT;
66 return socket_.Bind(ip_end_point);
69 void UDPSocket::Disconnect() {
70 is_connected_ = false;
71 socket_.Close();
72 read_callback_.Reset();
73 recv_from_callback_.Reset();
74 send_to_callback_.Reset();
75 multicast_groups_.clear();
78 void UDPSocket::Read(int count, const ReadCompletionCallback& callback) {
79 DCHECK(!callback.is_null());
81 if (!read_callback_.is_null()) {
82 callback.Run(net::ERR_IO_PENDING, NULL);
83 return;
84 } else {
85 read_callback_ = callback;
88 int result = net::ERR_FAILED;
89 scoped_refptr<net::IOBuffer> io_buffer;
90 do {
91 if (count < 0) {
92 result = net::ERR_INVALID_ARGUMENT;
93 break;
96 if (!socket_.is_connected()) {
97 result = net::ERR_SOCKET_NOT_CONNECTED;
98 break;
101 io_buffer = new net::IOBuffer(count);
102 result = socket_.Read(
103 io_buffer.get(),
104 count,
105 base::Bind(
106 &UDPSocket::OnReadComplete, base::Unretained(this), io_buffer));
107 } while (false);
109 if (result != net::ERR_IO_PENDING)
110 OnReadComplete(io_buffer, result);
113 int UDPSocket::WriteImpl(net::IOBuffer* io_buffer,
114 int io_buffer_size,
115 const net::CompletionCallback& callback) {
116 if (!socket_.is_connected())
117 return net::ERR_SOCKET_NOT_CONNECTED;
118 else
119 return socket_.Write(io_buffer, io_buffer_size, callback);
122 void UDPSocket::RecvFrom(int count,
123 const RecvFromCompletionCallback& callback) {
124 DCHECK(!callback.is_null());
126 if (!recv_from_callback_.is_null()) {
127 callback.Run(net::ERR_IO_PENDING, NULL, std::string(), 0);
128 return;
129 } else {
130 recv_from_callback_ = callback;
133 int result = net::ERR_FAILED;
134 scoped_refptr<net::IOBuffer> io_buffer;
135 scoped_refptr<IPEndPoint> address;
136 do {
137 if (count < 0) {
138 result = net::ERR_INVALID_ARGUMENT;
139 break;
142 if (!socket_.is_connected()) {
143 result = net::ERR_SOCKET_NOT_CONNECTED;
144 break;
147 io_buffer = new net::IOBuffer(count);
148 address = new IPEndPoint();
149 result = socket_.RecvFrom(io_buffer.get(),
150 count,
151 &address->data,
152 base::Bind(&UDPSocket::OnRecvFromComplete,
153 base::Unretained(this),
154 io_buffer,
155 address));
156 } while (false);
158 if (result != net::ERR_IO_PENDING)
159 OnRecvFromComplete(io_buffer, address, result);
162 void UDPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer,
163 int byte_count,
164 const std::string& address,
165 int port,
166 const CompletionCallback& callback) {
167 DCHECK(!callback.is_null());
169 if (!send_to_callback_.is_null()) {
170 // TODO(penghuang): Put requests in a pending queue to support multiple
171 // sendTo calls.
172 callback.Run(net::ERR_IO_PENDING);
173 return;
174 } else {
175 send_to_callback_ = callback;
178 int result = net::ERR_FAILED;
179 do {
180 net::IPEndPoint ip_end_point;
181 if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) {
182 result = net::ERR_ADDRESS_INVALID;
183 break;
186 if (!socket_.is_connected()) {
187 result = net::ERR_SOCKET_NOT_CONNECTED;
188 break;
191 result = socket_.SendTo(
192 io_buffer.get(),
193 byte_count,
194 ip_end_point,
195 base::Bind(&UDPSocket::OnSendToComplete, base::Unretained(this)));
196 } while (false);
198 if (result != net::ERR_IO_PENDING)
199 OnSendToComplete(result);
202 bool UDPSocket::IsConnected() { return is_connected_; }
204 bool UDPSocket::GetPeerAddress(net::IPEndPoint* address) {
205 return !socket_.GetPeerAddress(address);
208 bool UDPSocket::GetLocalAddress(net::IPEndPoint* address) {
209 return !socket_.GetLocalAddress(address);
212 Socket::SocketType UDPSocket::GetSocketType() const { return Socket::TYPE_UDP; }
214 void UDPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
215 int result) {
216 DCHECK(!read_callback_.is_null());
217 read_callback_.Run(result, io_buffer);
218 read_callback_.Reset();
221 void UDPSocket::OnRecvFromComplete(scoped_refptr<net::IOBuffer> io_buffer,
222 scoped_refptr<IPEndPoint> address,
223 int result) {
224 DCHECK(!recv_from_callback_.is_null());
225 std::string ip;
226 int port = 0;
227 if (result > 0 && address.get()) {
228 IPEndPointToStringAndPort(address->data, &ip, &port);
230 recv_from_callback_.Run(result, io_buffer, ip, port);
231 recv_from_callback_.Reset();
234 void UDPSocket::OnSendToComplete(int result) {
235 DCHECK(!send_to_callback_.is_null());
236 send_to_callback_.Run(result);
237 send_to_callback_.Reset();
240 bool UDPSocket::IsBound() { return socket_.is_connected(); }
242 int UDPSocket::JoinGroup(const std::string& address) {
243 net::IPAddressNumber ip;
244 if (!net::ParseIPLiteralToNumber(address, &ip))
245 return net::ERR_ADDRESS_INVALID;
247 std::string normalized_address = net::IPAddressToString(ip);
248 std::vector<std::string>::iterator find_result = std::find(
249 multicast_groups_.begin(), multicast_groups_.end(), normalized_address);
250 if (find_result != multicast_groups_.end())
251 return net::ERR_ADDRESS_INVALID;
253 int rv = socket_.JoinGroup(ip);
254 if (rv == 0)
255 multicast_groups_.push_back(normalized_address);
256 return rv;
259 int UDPSocket::LeaveGroup(const std::string& address) {
260 net::IPAddressNumber ip;
261 if (!net::ParseIPLiteralToNumber(address, &ip))
262 return net::ERR_ADDRESS_INVALID;
264 std::string normalized_address = net::IPAddressToString(ip);
265 std::vector<std::string>::iterator find_result = std::find(
266 multicast_groups_.begin(), multicast_groups_.end(), normalized_address);
267 if (find_result == multicast_groups_.end())
268 return net::ERR_ADDRESS_INVALID;
270 int rv = socket_.LeaveGroup(ip);
271 if (rv == 0)
272 multicast_groups_.erase(find_result);
273 return rv;
276 int UDPSocket::SetMulticastTimeToLive(int ttl) {
277 return socket_.SetMulticastTimeToLive(ttl);
280 int UDPSocket::SetMulticastLoopbackMode(bool loopback) {
281 return socket_.SetMulticastLoopbackMode(loopback);
284 const std::vector<std::string>& UDPSocket::GetJoinedGroups() const {
285 return multicast_groups_;
288 ResumableUDPSocket::ResumableUDPSocket(const std::string& owner_extension_id)
289 : UDPSocket(owner_extension_id),
290 persistent_(false),
291 buffer_size_(0),
292 paused_(false) {}
294 bool ResumableUDPSocket::IsPersistent() const { return persistent(); }
296 } // namespace extensions