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