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