| 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 "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> >* | |
| 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 UDPSocket::~UDPSocket() { Disconnect(); } | |
| 36 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 202 bool UDPSocket::IsConnected() { return is_connected_; } | |
| 203 | |
| 204 bool UDPSocket::GetPeerAddress(net::IPEndPoint* address) { | |
| 205 return !socket_.GetPeerAddress(address); | |
| 206 } | |
| 207 | |
| 208 bool UDPSocket::GetLocalAddress(net::IPEndPoint* address) { | |
| 209 return !socket_.GetLocalAddress(address); | |
| 210 } | |
| 211 | |
| 212 Socket::SocketType UDPSocket::GetSocketType() const { return Socket::TYPE_UDP; } | |
| 213 | |
| 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 | |
| 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 | |
| 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 | |
| 240 bool UDPSocket::IsBound() { return socket_.is_connected(); } | |
| 241 | |
| 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 | |
| 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 | |
| 276 int UDPSocket::SetMulticastTimeToLive(int ttl) { | |
| 277 return socket_.SetMulticastTimeToLive(ttl); | |
| 278 } | |
| 279 | |
| 280 int UDPSocket::SetMulticastLoopbackMode(bool loopback) { | |
| 281 return socket_.SetMulticastLoopbackMode(loopback); | |
| 282 } | |
| 283 | |
| 284 const std::vector<std::string>& UDPSocket::GetJoinedGroups() const { | |
| 285 return multicast_groups_; | |
| 286 } | |
| 287 | |
| 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 | |
| 294 bool ResumableUDPSocket::IsPersistent() const { return persistent(); } | |
| 295 | |
| 296 } // namespace extensions | |
| OLD | NEW |