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_
.Open(ip_end_point
.GetFamily());
53 if (result
!= net::OK
)
56 result
= socket_
.Connect(ip_end_point
);
57 if (result
!= net::OK
) {
67 int UDPSocket::Bind(const std::string
& address
, uint16 port
) {
69 return net::ERR_CONNECTION_FAILED
;
71 net::IPEndPoint ip_end_point
;
72 if (!StringAndPortToIPEndPoint(address
, port
, &ip_end_point
))
73 return net::ERR_INVALID_ARGUMENT
;
75 int result
= socket_
.Open(ip_end_point
.GetFamily());
76 if (result
!= net::OK
)
79 result
= socket_
.Bind(ip_end_point
);
80 if (result
!= net::OK
)
85 void UDPSocket::Disconnect() {
86 is_connected_
= false;
88 read_callback_
.Reset();
89 recv_from_callback_
.Reset();
90 send_to_callback_
.Reset();
91 multicast_groups_
.clear();
94 void UDPSocket::Read(int count
, const ReadCompletionCallback
& callback
) {
95 DCHECK(!callback
.is_null());
97 if (!read_callback_
.is_null()) {
98 callback
.Run(net::ERR_IO_PENDING
, NULL
);
101 read_callback_
= callback
;
104 int result
= net::ERR_FAILED
;
105 scoped_refptr
<net::IOBuffer
> io_buffer
;
108 result
= net::ERR_INVALID_ARGUMENT
;
112 if (!socket_
.is_connected()) {
113 result
= net::ERR_SOCKET_NOT_CONNECTED
;
117 io_buffer
= new net::IOBuffer(count
);
118 result
= socket_
.Read(
122 &UDPSocket::OnReadComplete
, base::Unretained(this), io_buffer
));
125 if (result
!= net::ERR_IO_PENDING
)
126 OnReadComplete(io_buffer
, result
);
129 int UDPSocket::WriteImpl(net::IOBuffer
* io_buffer
,
131 const net::CompletionCallback
& callback
) {
132 if (!socket_
.is_connected())
133 return net::ERR_SOCKET_NOT_CONNECTED
;
135 return socket_
.Write(io_buffer
, io_buffer_size
, callback
);
138 void UDPSocket::RecvFrom(int count
,
139 const RecvFromCompletionCallback
& callback
) {
140 DCHECK(!callback
.is_null());
142 if (!recv_from_callback_
.is_null()) {
143 callback
.Run(net::ERR_IO_PENDING
, NULL
, std::string(), 0);
146 recv_from_callback_
= callback
;
149 int result
= net::ERR_FAILED
;
150 scoped_refptr
<net::IOBuffer
> io_buffer
;
151 scoped_refptr
<IPEndPoint
> address
;
154 result
= net::ERR_INVALID_ARGUMENT
;
158 if (!socket_
.is_connected()) {
159 result
= net::ERR_SOCKET_NOT_CONNECTED
;
163 io_buffer
= new net::IOBuffer(count
);
164 address
= new IPEndPoint();
165 result
= socket_
.RecvFrom(io_buffer
.get(),
168 base::Bind(&UDPSocket::OnRecvFromComplete
,
169 base::Unretained(this),
174 if (result
!= net::ERR_IO_PENDING
)
175 OnRecvFromComplete(io_buffer
, address
, result
);
178 void UDPSocket::SendTo(scoped_refptr
<net::IOBuffer
> io_buffer
,
180 const std::string
& address
,
182 const CompletionCallback
& callback
) {
183 DCHECK(!callback
.is_null());
185 if (!send_to_callback_
.is_null()) {
186 // TODO(penghuang): Put requests in a pending queue to support multiple
188 callback
.Run(net::ERR_IO_PENDING
);
191 send_to_callback_
= callback
;
194 int result
= net::ERR_FAILED
;
196 net::IPEndPoint ip_end_point
;
197 if (!StringAndPortToIPEndPoint(address
, port
, &ip_end_point
)) {
198 result
= net::ERR_ADDRESS_INVALID
;
202 if (!socket_
.is_connected()) {
203 result
= net::ERR_SOCKET_NOT_CONNECTED
;
207 result
= socket_
.SendTo(
211 base::Bind(&UDPSocket::OnSendToComplete
, base::Unretained(this)));
214 if (result
!= net::ERR_IO_PENDING
)
215 OnSendToComplete(result
);
218 bool UDPSocket::IsConnected() { return is_connected_
; }
220 bool UDPSocket::GetPeerAddress(net::IPEndPoint
* address
) {
221 return !socket_
.GetPeerAddress(address
);
224 bool UDPSocket::GetLocalAddress(net::IPEndPoint
* address
) {
225 return !socket_
.GetLocalAddress(address
);
228 Socket::SocketType
UDPSocket::GetSocketType() const { return Socket::TYPE_UDP
; }
230 void UDPSocket::OnReadComplete(scoped_refptr
<net::IOBuffer
> io_buffer
,
232 DCHECK(!read_callback_
.is_null());
233 read_callback_
.Run(result
, io_buffer
);
234 read_callback_
.Reset();
237 void UDPSocket::OnRecvFromComplete(scoped_refptr
<net::IOBuffer
> io_buffer
,
238 scoped_refptr
<IPEndPoint
> address
,
240 DCHECK(!recv_from_callback_
.is_null());
243 if (result
> 0 && address
.get()) {
244 IPEndPointToStringAndPort(address
->data
, &ip
, &port
);
246 recv_from_callback_
.Run(result
, io_buffer
, ip
, port
);
247 recv_from_callback_
.Reset();
250 void UDPSocket::OnSendToComplete(int result
) {
251 DCHECK(!send_to_callback_
.is_null());
252 send_to_callback_
.Run(result
);
253 send_to_callback_
.Reset();
256 bool UDPSocket::IsBound() { return socket_
.is_connected(); }
258 int UDPSocket::JoinGroup(const std::string
& address
) {
259 net::IPAddressNumber ip
;
260 if (!net::ParseIPLiteralToNumber(address
, &ip
))
261 return net::ERR_ADDRESS_INVALID
;
263 std::string normalized_address
= net::IPAddressToString(ip
);
264 std::vector
<std::string
>::iterator find_result
= std::find(
265 multicast_groups_
.begin(), multicast_groups_
.end(), normalized_address
);
266 if (find_result
!= multicast_groups_
.end())
267 return net::ERR_ADDRESS_INVALID
;
269 int rv
= socket_
.JoinGroup(ip
);
271 multicast_groups_
.push_back(normalized_address
);
275 int UDPSocket::LeaveGroup(const std::string
& address
) {
276 net::IPAddressNumber ip
;
277 if (!net::ParseIPLiteralToNumber(address
, &ip
))
278 return net::ERR_ADDRESS_INVALID
;
280 std::string normalized_address
= net::IPAddressToString(ip
);
281 std::vector
<std::string
>::iterator find_result
= std::find(
282 multicast_groups_
.begin(), multicast_groups_
.end(), normalized_address
);
283 if (find_result
== multicast_groups_
.end())
284 return net::ERR_ADDRESS_INVALID
;
286 int rv
= socket_
.LeaveGroup(ip
);
288 multicast_groups_
.erase(find_result
);
292 int UDPSocket::SetMulticastTimeToLive(int ttl
) {
293 return socket_
.SetMulticastTimeToLive(ttl
);
296 int UDPSocket::SetMulticastLoopbackMode(bool loopback
) {
297 return socket_
.SetMulticastLoopbackMode(loopback
);
300 int UDPSocket::SetBroadcast(bool enabled
) {
301 if (!socket_
.is_connected()) {
302 return net::ERR_SOCKET_NOT_CONNECTED
;
304 return socket_
.SetBroadcast(enabled
);
307 const std::vector
<std::string
>& UDPSocket::GetJoinedGroups() const {
308 return multicast_groups_
;
311 ResumableUDPSocket::ResumableUDPSocket(const std::string
& owner_extension_id
)
312 : UDPSocket(owner_extension_id
),
317 bool ResumableUDPSocket::IsPersistent() const { return persistent(); }
319 } // namespace extensions