• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "extensions/browser/api/socket/udp_socket.h"
6 
7 #include <algorithm>
8 
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"
15 
16 namespace extensions {
17 
18 static base::LazyInstance<
19     BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> > >
20     g_factory = LAZY_INSTANCE_INITIALIZER;
21 
22 // static
23 template <>
24 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> >*
GetFactoryInstance()25 ApiResourceManager<ResumableUDPSocket>::GetFactoryInstance() {
26   return g_factory.Pointer();
27 }
28 
UDPSocket(const std::string & owner_extension_id)29 UDPSocket::UDPSocket(const std::string& owner_extension_id)
30     : Socket(owner_extension_id),
31       socket_(net::DatagramSocket::DEFAULT_BIND,
32               net::RandIntCallback(),
33               NULL,
34               net::NetLog::Source()) {}
35 
~UDPSocket()36 UDPSocket::~UDPSocket() { Disconnect(); }
37 
Connect(const std::string & address,int port,const CompletionCallback & callback)38 void UDPSocket::Connect(const std::string& address,
39                         int port,
40                         const CompletionCallback& callback) {
41   int result = net::ERR_CONNECTION_FAILED;
42   do {
43     if (is_connected_)
44       break;
45 
46     net::IPEndPoint ip_end_point;
47     if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) {
48       result = net::ERR_ADDRESS_INVALID;
49       break;
50     }
51 
52     result = socket_.Connect(ip_end_point);
53     is_connected_ = (result == net::OK);
54   } while (false);
55 
56   callback.Run(result);
57 }
58 
Bind(const std::string & address,int port)59 int UDPSocket::Bind(const std::string& address, int port) {
60   if (IsBound())
61     return net::ERR_CONNECTION_FAILED;
62 
63   net::IPEndPoint ip_end_point;
64   if (!StringAndPortToIPEndPoint(address, port, &ip_end_point))
65     return net::ERR_INVALID_ARGUMENT;
66 
67   return socket_.Bind(ip_end_point);
68 }
69 
Disconnect()70 void UDPSocket::Disconnect() {
71   is_connected_ = false;
72   socket_.Close();
73   read_callback_.Reset();
74   recv_from_callback_.Reset();
75   send_to_callback_.Reset();
76   multicast_groups_.clear();
77 }
78 
Read(int count,const ReadCompletionCallback & callback)79 void UDPSocket::Read(int count, const ReadCompletionCallback& callback) {
80   DCHECK(!callback.is_null());
81 
82   if (!read_callback_.is_null()) {
83     callback.Run(net::ERR_IO_PENDING, NULL);
84     return;
85   } else {
86     read_callback_ = callback;
87   }
88 
89   int result = net::ERR_FAILED;
90   scoped_refptr<net::IOBuffer> io_buffer;
91   do {
92     if (count < 0) {
93       result = net::ERR_INVALID_ARGUMENT;
94       break;
95     }
96 
97     if (!socket_.is_connected()) {
98       result = net::ERR_SOCKET_NOT_CONNECTED;
99       break;
100     }
101 
102     io_buffer = new net::IOBuffer(count);
103     result = socket_.Read(
104         io_buffer.get(),
105         count,
106         base::Bind(
107             &UDPSocket::OnReadComplete, base::Unretained(this), io_buffer));
108   } while (false);
109 
110   if (result != net::ERR_IO_PENDING)
111     OnReadComplete(io_buffer, result);
112 }
113 
WriteImpl(net::IOBuffer * io_buffer,int io_buffer_size,const net::CompletionCallback & callback)114 int UDPSocket::WriteImpl(net::IOBuffer* io_buffer,
115                          int io_buffer_size,
116                          const net::CompletionCallback& callback) {
117   if (!socket_.is_connected())
118     return net::ERR_SOCKET_NOT_CONNECTED;
119   else
120     return socket_.Write(io_buffer, io_buffer_size, callback);
121 }
122 
RecvFrom(int count,const RecvFromCompletionCallback & callback)123 void UDPSocket::RecvFrom(int count,
124                          const RecvFromCompletionCallback& callback) {
125   DCHECK(!callback.is_null());
126 
127   if (!recv_from_callback_.is_null()) {
128     callback.Run(net::ERR_IO_PENDING, NULL, std::string(), 0);
129     return;
130   } else {
131     recv_from_callback_ = callback;
132   }
133 
134   int result = net::ERR_FAILED;
135   scoped_refptr<net::IOBuffer> io_buffer;
136   scoped_refptr<IPEndPoint> address;
137   do {
138     if (count < 0) {
139       result = net::ERR_INVALID_ARGUMENT;
140       break;
141     }
142 
143     if (!socket_.is_connected()) {
144       result = net::ERR_SOCKET_NOT_CONNECTED;
145       break;
146     }
147 
148     io_buffer = new net::IOBuffer(count);
149     address = new IPEndPoint();
150     result = socket_.RecvFrom(io_buffer.get(),
151                               count,
152                               &address->data,
153                               base::Bind(&UDPSocket::OnRecvFromComplete,
154                                          base::Unretained(this),
155                                          io_buffer,
156                                          address));
157   } while (false);
158 
159   if (result != net::ERR_IO_PENDING)
160     OnRecvFromComplete(io_buffer, address, result);
161 }
162 
SendTo(scoped_refptr<net::IOBuffer> io_buffer,int byte_count,const std::string & address,int port,const CompletionCallback & callback)163 void UDPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer,
164                        int byte_count,
165                        const std::string& address,
166                        int port,
167                        const CompletionCallback& callback) {
168   DCHECK(!callback.is_null());
169 
170   if (!send_to_callback_.is_null()) {
171     // TODO(penghuang): Put requests in a pending queue to support multiple
172     // sendTo calls.
173     callback.Run(net::ERR_IO_PENDING);
174     return;
175   } else {
176     send_to_callback_ = callback;
177   }
178 
179   int result = net::ERR_FAILED;
180   do {
181     net::IPEndPoint ip_end_point;
182     if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) {
183       result = net::ERR_ADDRESS_INVALID;
184       break;
185     }
186 
187     if (!socket_.is_connected()) {
188       result = net::ERR_SOCKET_NOT_CONNECTED;
189       break;
190     }
191 
192     result = socket_.SendTo(
193         io_buffer.get(),
194         byte_count,
195         ip_end_point,
196         base::Bind(&UDPSocket::OnSendToComplete, base::Unretained(this)));
197   } while (false);
198 
199   if (result != net::ERR_IO_PENDING)
200     OnSendToComplete(result);
201 }
202 
IsConnected()203 bool UDPSocket::IsConnected() { return is_connected_; }
204 
GetPeerAddress(net::IPEndPoint * address)205 bool UDPSocket::GetPeerAddress(net::IPEndPoint* address) {
206   return !socket_.GetPeerAddress(address);
207 }
208 
GetLocalAddress(net::IPEndPoint * address)209 bool UDPSocket::GetLocalAddress(net::IPEndPoint* address) {
210   return !socket_.GetLocalAddress(address);
211 }
212 
GetSocketType() const213 Socket::SocketType UDPSocket::GetSocketType() const { return Socket::TYPE_UDP; }
214 
OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,int result)215 void UDPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
216                                int result) {
217   DCHECK(!read_callback_.is_null());
218   read_callback_.Run(result, io_buffer);
219   read_callback_.Reset();
220 }
221 
OnRecvFromComplete(scoped_refptr<net::IOBuffer> io_buffer,scoped_refptr<IPEndPoint> address,int result)222 void UDPSocket::OnRecvFromComplete(scoped_refptr<net::IOBuffer> io_buffer,
223                                    scoped_refptr<IPEndPoint> address,
224                                    int result) {
225   DCHECK(!recv_from_callback_.is_null());
226   std::string ip;
227   int port = 0;
228   if (result > 0 && address.get()) {
229     IPEndPointToStringAndPort(address->data, &ip, &port);
230   }
231   recv_from_callback_.Run(result, io_buffer, ip, port);
232   recv_from_callback_.Reset();
233 }
234 
OnSendToComplete(int result)235 void UDPSocket::OnSendToComplete(int result) {
236   DCHECK(!send_to_callback_.is_null());
237   send_to_callback_.Run(result);
238   send_to_callback_.Reset();
239 }
240 
IsBound()241 bool UDPSocket::IsBound() { return socket_.is_connected(); }
242 
JoinGroup(const std::string & address)243 int UDPSocket::JoinGroup(const std::string& address) {
244   net::IPAddressNumber ip;
245   if (!net::ParseIPLiteralToNumber(address, &ip))
246     return net::ERR_ADDRESS_INVALID;
247 
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;
253 
254   int rv = socket_.JoinGroup(ip);
255   if (rv == 0)
256     multicast_groups_.push_back(normalized_address);
257   return rv;
258 }
259 
LeaveGroup(const std::string & 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;
264 
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;
270 
271   int rv = socket_.LeaveGroup(ip);
272   if (rv == 0)
273     multicast_groups_.erase(find_result);
274   return rv;
275 }
276 
SetMulticastTimeToLive(int ttl)277 int UDPSocket::SetMulticastTimeToLive(int ttl) {
278   return socket_.SetMulticastTimeToLive(ttl);
279 }
280 
SetMulticastLoopbackMode(bool loopback)281 int UDPSocket::SetMulticastLoopbackMode(bool loopback) {
282   return socket_.SetMulticastLoopbackMode(loopback);
283 }
284 
GetJoinedGroups() const285 const std::vector<std::string>& UDPSocket::GetJoinedGroups() const {
286   return multicast_groups_;
287 }
288 
ResumableUDPSocket(const std::string & owner_extension_id)289 ResumableUDPSocket::ResumableUDPSocket(const std::string& owner_extension_id)
290     : UDPSocket(owner_extension_id),
291       persistent_(false),
292       buffer_size_(0),
293       paused_(false) {}
294 
IsPersistent() const295 bool ResumableUDPSocket::IsPersistent() const { return persistent(); }
296 
297 }  // namespace extensions
298