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"
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
;
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(),
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
;
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
)
52 result
= socket_
.Connect(ip_end_point
);
53 if (result
!= net::OK
) {
63 int UDPSocket::Bind(const std::string
& address
, uint16 port
) {
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
)
75 result
= socket_
.Bind(ip_end_point
);
76 if (result
!= net::OK
)
81 void UDPSocket::Disconnect() {
82 is_connected_
= false;
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
);
97 read_callback_
= callback
;
100 int result
= net::ERR_FAILED
;
101 scoped_refptr
<net::IOBuffer
> io_buffer
;
104 result
= net::ERR_INVALID_ARGUMENT
;
108 if (!socket_
.is_connected()) {
109 result
= net::ERR_SOCKET_NOT_CONNECTED
;
113 io_buffer
= new net::IOBuffer(count
);
114 result
= socket_
.Read(
118 &UDPSocket::OnReadComplete
, base::Unretained(this), io_buffer
));
121 if (result
!= net::ERR_IO_PENDING
)
122 OnReadComplete(io_buffer
, result
);
125 int UDPSocket::WriteImpl(net::IOBuffer
* io_buffer
,
127 const net::CompletionCallback
& callback
) {
128 if (!socket_
.is_connected())
129 return net::ERR_SOCKET_NOT_CONNECTED
;
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);
142 recv_from_callback_
= callback
;
145 int result
= net::ERR_FAILED
;
146 scoped_refptr
<net::IOBuffer
> io_buffer
;
147 scoped_refptr
<IPEndPoint
> address
;
150 result
= net::ERR_INVALID_ARGUMENT
;
154 if (!socket_
.is_connected()) {
155 result
= net::ERR_SOCKET_NOT_CONNECTED
;
159 io_buffer
= new net::IOBuffer(count
);
160 address
= new IPEndPoint();
161 result
= socket_
.RecvFrom(io_buffer
.get(),
164 base::Bind(&UDPSocket::OnRecvFromComplete
,
165 base::Unretained(this),
170 if (result
!= net::ERR_IO_PENDING
)
171 OnRecvFromComplete(io_buffer
, address
, result
);
174 void UDPSocket::SendTo(scoped_refptr
<net::IOBuffer
> io_buffer
,
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
183 callback
.Run(net::ERR_IO_PENDING
);
186 send_to_callback_
= callback
;
189 int result
= net::ERR_FAILED
;
191 if (!socket_
.is_connected()) {
192 result
= net::ERR_SOCKET_NOT_CONNECTED
;
196 result
= socket_
.SendTo(
197 io_buffer
.get(), byte_count
, address
,
198 base::Bind(&UDPSocket::OnSendToComplete
, base::Unretained(this)));
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
,
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
,
227 DCHECK(!recv_from_callback_
.is_null());
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
);
258 multicast_groups_
.push_back(normalized_address
);
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
);
275 multicast_groups_
.erase(find_result
);
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
),
304 bool ResumableUDPSocket::IsPersistent() const { return persistent(); }
306 } // namespace extensions