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