| OLD | NEW |
| (Empty) |
| 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< | |
| 18 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> > > | |
| 19 g_factory = LAZY_INSTANCE_INITIALIZER; | |
| 20 | |
| 21 // static | |
| 22 template <> | |
| 23 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> >* | |
| 24 ApiResourceManager<ResumableUDPSocket>::GetFactoryInstance() { | |
| 25 return g_factory.Pointer(); | |
| 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 | |
| OLD | NEW |