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 std::string
& address
,
40 const CompletionCallback
& callback
) {
41 int result
= net::ERR_CONNECTION_FAILED
;
46 net::IPEndPoint ip_end_point
;
47 if (!StringAndPortToIPEndPoint(address
, port
, &ip_end_point
)) {
48 result
= net::ERR_ADDRESS_INVALID
;
52 result
= socket_
.Connect(ip_end_point
);
53 is_connected_
= (result
== net::OK
);
59 int UDPSocket::Bind(const std::string
& address
, uint16 port
) {
61 return net::ERR_CONNECTION_FAILED
;
63 net::IPEndPoint ip_end_point
;
64 if (!StringAndPortToIPEndPoint(address
, port
, &ip_end_point
))
65 return net::ERR_INVALID_ARGUMENT
;
67 return socket_
.Bind(ip_end_point
);
70 void UDPSocket::Disconnect() {
71 is_connected_
= false;
73 read_callback_
.Reset();
74 recv_from_callback_
.Reset();
75 send_to_callback_
.Reset();
76 multicast_groups_
.clear();
79 void UDPSocket::Read(int count
, const ReadCompletionCallback
& callback
) {
80 DCHECK(!callback
.is_null());
82 if (!read_callback_
.is_null()) {
83 callback
.Run(net::ERR_IO_PENDING
, NULL
);
86 read_callback_
= callback
;
89 int result
= net::ERR_FAILED
;
90 scoped_refptr
<net::IOBuffer
> io_buffer
;
93 result
= net::ERR_INVALID_ARGUMENT
;
97 if (!socket_
.is_connected()) {
98 result
= net::ERR_SOCKET_NOT_CONNECTED
;
102 io_buffer
= new net::IOBuffer(count
);
103 result
= socket_
.Read(
107 &UDPSocket::OnReadComplete
, base::Unretained(this), io_buffer
));
110 if (result
!= net::ERR_IO_PENDING
)
111 OnReadComplete(io_buffer
, result
);
114 int UDPSocket::WriteImpl(net::IOBuffer
* io_buffer
,
116 const net::CompletionCallback
& callback
) {
117 if (!socket_
.is_connected())
118 return net::ERR_SOCKET_NOT_CONNECTED
;
120 return socket_
.Write(io_buffer
, io_buffer_size
, callback
);
123 void UDPSocket::RecvFrom(int count
,
124 const RecvFromCompletionCallback
& callback
) {
125 DCHECK(!callback
.is_null());
127 if (!recv_from_callback_
.is_null()) {
128 callback
.Run(net::ERR_IO_PENDING
, NULL
, std::string(), 0);
131 recv_from_callback_
= callback
;
134 int result
= net::ERR_FAILED
;
135 scoped_refptr
<net::IOBuffer
> io_buffer
;
136 scoped_refptr
<IPEndPoint
> address
;
139 result
= net::ERR_INVALID_ARGUMENT
;
143 if (!socket_
.is_connected()) {
144 result
= net::ERR_SOCKET_NOT_CONNECTED
;
148 io_buffer
= new net::IOBuffer(count
);
149 address
= new IPEndPoint();
150 result
= socket_
.RecvFrom(io_buffer
.get(),
153 base::Bind(&UDPSocket::OnRecvFromComplete
,
154 base::Unretained(this),
159 if (result
!= net::ERR_IO_PENDING
)
160 OnRecvFromComplete(io_buffer
, address
, result
);
163 void UDPSocket::SendTo(scoped_refptr
<net::IOBuffer
> io_buffer
,
165 const std::string
& address
,
167 const CompletionCallback
& callback
) {
168 DCHECK(!callback
.is_null());
170 if (!send_to_callback_
.is_null()) {
171 // TODO(penghuang): Put requests in a pending queue to support multiple
173 callback
.Run(net::ERR_IO_PENDING
);
176 send_to_callback_
= callback
;
179 int result
= net::ERR_FAILED
;
181 net::IPEndPoint ip_end_point
;
182 if (!StringAndPortToIPEndPoint(address
, port
, &ip_end_point
)) {
183 result
= net::ERR_ADDRESS_INVALID
;
187 if (!socket_
.is_connected()) {
188 result
= net::ERR_SOCKET_NOT_CONNECTED
;
192 result
= socket_
.SendTo(
196 base::Bind(&UDPSocket::OnSendToComplete
, base::Unretained(this)));
199 if (result
!= net::ERR_IO_PENDING
)
200 OnSendToComplete(result
);
203 bool UDPSocket::IsConnected() { return is_connected_
; }
205 bool UDPSocket::GetPeerAddress(net::IPEndPoint
* address
) {
206 return !socket_
.GetPeerAddress(address
);
209 bool UDPSocket::GetLocalAddress(net::IPEndPoint
* address
) {
210 return !socket_
.GetLocalAddress(address
);
213 Socket::SocketType
UDPSocket::GetSocketType() const { return Socket::TYPE_UDP
; }
215 void UDPSocket::OnReadComplete(scoped_refptr
<net::IOBuffer
> io_buffer
,
217 DCHECK(!read_callback_
.is_null());
218 read_callback_
.Run(result
, io_buffer
);
219 read_callback_
.Reset();
222 void UDPSocket::OnRecvFromComplete(scoped_refptr
<net::IOBuffer
> io_buffer
,
223 scoped_refptr
<IPEndPoint
> address
,
225 DCHECK(!recv_from_callback_
.is_null());
228 if (result
> 0 && address
.get()) {
229 IPEndPointToStringAndPort(address
->data
, &ip
, &port
);
231 recv_from_callback_
.Run(result
, io_buffer
, ip
, port
);
232 recv_from_callback_
.Reset();
235 void UDPSocket::OnSendToComplete(int result
) {
236 DCHECK(!send_to_callback_
.is_null());
237 send_to_callback_
.Run(result
);
238 send_to_callback_
.Reset();
241 bool UDPSocket::IsBound() { return socket_
.is_connected(); }
243 int UDPSocket::JoinGroup(const std::string
& address
) {
244 net::IPAddressNumber ip
;
245 if (!net::ParseIPLiteralToNumber(address
, &ip
))
246 return net::ERR_ADDRESS_INVALID
;
248 std::string normalized_address
= net::IPAddressToString(ip
);
249 std::vector
<std::string
>::iterator find_result
= std::find(
250 multicast_groups_
.begin(), multicast_groups_
.end(), normalized_address
);
251 if (find_result
!= multicast_groups_
.end())
252 return net::ERR_ADDRESS_INVALID
;
254 int rv
= socket_
.JoinGroup(ip
);
256 multicast_groups_
.push_back(normalized_address
);
260 int UDPSocket::LeaveGroup(const std::string
& address
) {
261 net::IPAddressNumber ip
;
262 if (!net::ParseIPLiteralToNumber(address
, &ip
))
263 return net::ERR_ADDRESS_INVALID
;
265 std::string normalized_address
= net::IPAddressToString(ip
);
266 std::vector
<std::string
>::iterator find_result
= std::find(
267 multicast_groups_
.begin(), multicast_groups_
.end(), normalized_address
);
268 if (find_result
== multicast_groups_
.end())
269 return net::ERR_ADDRESS_INVALID
;
271 int rv
= socket_
.LeaveGroup(ip
);
273 multicast_groups_
.erase(find_result
);
277 int UDPSocket::SetMulticastTimeToLive(int ttl
) {
278 return socket_
.SetMulticastTimeToLive(ttl
);
281 int UDPSocket::SetMulticastLoopbackMode(bool loopback
) {
282 return socket_
.SetMulticastLoopbackMode(loopback
);
285 const std::vector
<std::string
>& UDPSocket::GetJoinedGroups() const {
286 return multicast_groups_
;
289 ResumableUDPSocket::ResumableUDPSocket(const std::string
& owner_extension_id
)
290 : UDPSocket(owner_extension_id
),
295 bool ResumableUDPSocket::IsPersistent() const { return persistent(); }
297 } // namespace extensions