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 "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
;
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(),
33 net::NetLog::Source()) {}
35 UDPSocket::~UDPSocket() { Disconnect(); }
37 void UDPSocket::Connect(const std::string
& address
,
39 const CompletionCallback
& callback
) {
40 int result
= net::ERR_CONNECTION_FAILED
;
45 net::IPEndPoint ip_end_point
;
46 if (!StringAndPortToIPEndPoint(address
, port
, &ip_end_point
)) {
47 result
= net::ERR_ADDRESS_INVALID
;
51 result
= socket_
.Connect(ip_end_point
);
52 is_connected_
= (result
== net::OK
);
58 int UDPSocket::Bind(const std::string
& address
, int port
) {
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;
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
);
85 read_callback_
= callback
;
88 int result
= net::ERR_FAILED
;
89 scoped_refptr
<net::IOBuffer
> io_buffer
;
92 result
= net::ERR_INVALID_ARGUMENT
;
96 if (!socket_
.is_connected()) {
97 result
= net::ERR_SOCKET_NOT_CONNECTED
;
101 io_buffer
= new net::IOBuffer(count
);
102 result
= socket_
.Read(
106 &UDPSocket::OnReadComplete
, base::Unretained(this), io_buffer
));
109 if (result
!= net::ERR_IO_PENDING
)
110 OnReadComplete(io_buffer
, result
);
113 int UDPSocket::WriteImpl(net::IOBuffer
* io_buffer
,
115 const net::CompletionCallback
& callback
) {
116 if (!socket_
.is_connected())
117 return net::ERR_SOCKET_NOT_CONNECTED
;
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);
130 recv_from_callback_
= callback
;
133 int result
= net::ERR_FAILED
;
134 scoped_refptr
<net::IOBuffer
> io_buffer
;
135 scoped_refptr
<IPEndPoint
> address
;
138 result
= net::ERR_INVALID_ARGUMENT
;
142 if (!socket_
.is_connected()) {
143 result
= net::ERR_SOCKET_NOT_CONNECTED
;
147 io_buffer
= new net::IOBuffer(count
);
148 address
= new IPEndPoint();
149 result
= socket_
.RecvFrom(io_buffer
.get(),
152 base::Bind(&UDPSocket::OnRecvFromComplete
,
153 base::Unretained(this),
158 if (result
!= net::ERR_IO_PENDING
)
159 OnRecvFromComplete(io_buffer
, address
, result
);
162 void UDPSocket::SendTo(scoped_refptr
<net::IOBuffer
> io_buffer
,
164 const std::string
& address
,
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
172 callback
.Run(net::ERR_IO_PENDING
);
175 send_to_callback_
= callback
;
178 int result
= net::ERR_FAILED
;
180 net::IPEndPoint ip_end_point
;
181 if (!StringAndPortToIPEndPoint(address
, port
, &ip_end_point
)) {
182 result
= net::ERR_ADDRESS_INVALID
;
186 if (!socket_
.is_connected()) {
187 result
= net::ERR_SOCKET_NOT_CONNECTED
;
191 result
= socket_
.SendTo(
195 base::Bind(&UDPSocket::OnSendToComplete
, base::Unretained(this)));
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
,
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
,
224 DCHECK(!recv_from_callback_
.is_null());
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
);
255 multicast_groups_
.push_back(normalized_address
);
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
);
272 multicast_groups_
.erase(find_result
);
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
),
294 bool ResumableUDPSocket::IsPersistent() const { return persistent(); }
296 } // namespace extensions