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/tcp_socket.h" 6 7 #include "chrome/browser/extensions/api/api_resource.h" 8 #include "net/base/address_list.h" 9 #include "net/base/ip_endpoint.h" 10 #include "net/base/net_errors.h" 11 #include "net/base/rand_callback.h" 12 #include "net/socket/tcp_client_socket.h" 13 14 namespace extensions { 15 16 const char kTCPSocketTypeInvalidError[] = 17 "Cannot call both connect and listen on the same socket."; 18 const char kSocketListenError[] = "Could not listen on the specified port."; 19 20 TCPSocket::TCPSocket(const std::string& owner_extension_id) 21 : Socket(owner_extension_id), 22 socket_mode_(UNKNOWN) { 23 } 24 25 TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket, 26 const std::string& owner_extension_id, 27 bool is_connected) 28 : Socket(owner_extension_id), 29 socket_(tcp_client_socket), 30 socket_mode_(CLIENT) { 31 this->is_connected_ = is_connected; 32 } 33 34 TCPSocket::TCPSocket(net::TCPServerSocket* tcp_server_socket, 35 const std::string& owner_extension_id) 36 : Socket(owner_extension_id), 37 server_socket_(tcp_server_socket), 38 socket_mode_(SERVER) { 39 } 40 41 // static 42 TCPSocket* TCPSocket::CreateSocketForTesting( 43 net::TCPClientSocket* tcp_client_socket, 44 const std::string& owner_extension_id, 45 bool is_connected) { 46 return new TCPSocket(tcp_client_socket, owner_extension_id, is_connected); 47 } 48 49 // static 50 TCPSocket* TCPSocket::CreateServerSocketForTesting( 51 net::TCPServerSocket* tcp_server_socket, 52 const std::string& owner_extension_id) { 53 return new TCPSocket(tcp_server_socket, owner_extension_id); 54 } 55 56 TCPSocket::~TCPSocket() { 57 Disconnect(); 58 } 59 60 void TCPSocket::Connect(const std::string& address, 61 int port, 62 const CompletionCallback& callback) { 63 DCHECK(!callback.is_null()); 64 65 if (socket_mode_ == SERVER || !connect_callback_.is_null()) { 66 callback.Run(net::ERR_CONNECTION_FAILED); 67 return; 68 } 69 DCHECK(!server_socket_.get()); 70 socket_mode_ = CLIENT; 71 connect_callback_ = callback; 72 73 int result = net::ERR_CONNECTION_FAILED; 74 do { 75 if (is_connected_) 76 break; 77 78 net::AddressList address_list; 79 if (!StringAndPortToAddressList(address, port, &address_list)) { 80 result = net::ERR_ADDRESS_INVALID; 81 break; 82 } 83 84 socket_.reset(new net::TCPClientSocket(address_list, NULL, 85 net::NetLog::Source())); 86 87 connect_callback_ = callback; 88 result = socket_->Connect(base::Bind( 89 &TCPSocket::OnConnectComplete, base::Unretained(this))); 90 } while (false); 91 92 if (result != net::ERR_IO_PENDING) 93 OnConnectComplete(result); 94 } 95 96 void TCPSocket::Disconnect() { 97 is_connected_ = false; 98 if (socket_.get()) 99 socket_->Disconnect(); 100 server_socket_.reset(NULL); 101 } 102 103 int TCPSocket::Bind(const std::string& address, int port) { 104 return net::ERR_FAILED; 105 } 106 107 void TCPSocket::Read(int count, 108 const ReadCompletionCallback& callback) { 109 DCHECK(!callback.is_null()); 110 111 if (socket_mode_ != CLIENT) { 112 callback.Run(net::ERR_FAILED, NULL); 113 return; 114 } 115 116 if (!read_callback_.is_null()) { 117 callback.Run(net::ERR_IO_PENDING, NULL); 118 return; 119 } else { 120 read_callback_ = callback; 121 } 122 123 int result = net::ERR_FAILED; 124 scoped_refptr<net::IOBuffer> io_buffer; 125 do { 126 if (count < 0) { 127 result = net::ERR_INVALID_ARGUMENT; 128 break; 129 } 130 131 if (!socket_.get() || !IsConnected()) { 132 result = net::ERR_SOCKET_NOT_CONNECTED; 133 break; 134 } 135 136 io_buffer = new net::IOBuffer(count); 137 result = socket_->Read(io_buffer.get(), count, 138 base::Bind(&TCPSocket::OnReadComplete, base::Unretained(this), 139 io_buffer)); 140 } while (false); 141 142 if (result != net::ERR_IO_PENDING) 143 OnReadComplete(io_buffer, result); 144 } 145 146 void TCPSocket::RecvFrom(int count, 147 const RecvFromCompletionCallback& callback) { 148 callback.Run(net::ERR_FAILED, NULL, NULL, 0); 149 } 150 151 void TCPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer, 152 int byte_count, 153 const std::string& address, 154 int port, 155 const CompletionCallback& callback) { 156 callback.Run(net::ERR_FAILED); 157 } 158 159 bool TCPSocket::SetKeepAlive(bool enable, int delay) { 160 if (!socket_.get()) 161 return false; 162 return socket_->SetKeepAlive(enable, delay); 163 } 164 165 bool TCPSocket::SetNoDelay(bool no_delay) { 166 if (!socket_.get()) 167 return false; 168 return socket_->SetNoDelay(no_delay); 169 } 170 171 int TCPSocket::Listen(const std::string& address, int port, int backlog, 172 std::string* error_msg) { 173 if (socket_mode_ == CLIENT) { 174 *error_msg = kTCPSocketTypeInvalidError; 175 return net::ERR_NOT_IMPLEMENTED; 176 } 177 DCHECK(!socket_.get()); 178 socket_mode_ = SERVER; 179 180 scoped_ptr<net::IPEndPoint> bind_address(new net::IPEndPoint()); 181 if (!StringAndPortToIPEndPoint(address, port, bind_address.get())) 182 return net::ERR_INVALID_ARGUMENT; 183 184 if (!server_socket_.get()) { 185 server_socket_.reset(new net::TCPServerSocket(NULL, 186 net::NetLog::Source())); 187 } 188 int result = server_socket_->Listen(*bind_address, backlog); 189 if (result) 190 *error_msg = kSocketListenError; 191 return result; 192 } 193 194 void TCPSocket::Accept(const AcceptCompletionCallback &callback) { 195 if (socket_mode_ != SERVER || !server_socket_.get()) { 196 callback.Run(net::ERR_FAILED, NULL); 197 return; 198 } 199 200 // Limits to only 1 blocked accept call. 201 if (!accept_callback_.is_null()) { 202 callback.Run(net::ERR_FAILED, NULL); 203 return; 204 } 205 206 int result = server_socket_->Accept(&accept_socket_, base::Bind( 207 &TCPSocket::OnAccept, base::Unretained(this))); 208 if (result == net::ERR_IO_PENDING) { 209 accept_callback_ = callback; 210 } else if (result == net::OK) { 211 accept_callback_ = callback; 212 this->OnAccept(result); 213 } else { 214 callback.Run(result, NULL); 215 } 216 } 217 218 bool TCPSocket::IsConnected() { 219 RefreshConnectionStatus(); 220 return is_connected_; 221 } 222 223 bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) { 224 if (!socket_.get()) 225 return false; 226 return !socket_->GetPeerAddress(address); 227 } 228 229 bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) { 230 if (socket_.get()) { 231 return !socket_->GetLocalAddress(address); 232 } else if (server_socket_.get()) { 233 return !server_socket_->GetLocalAddress(address); 234 } else { 235 return false; 236 } 237 } 238 239 Socket::SocketType TCPSocket::GetSocketType() const { 240 return Socket::TYPE_TCP; 241 } 242 243 int TCPSocket::WriteImpl(net::IOBuffer* io_buffer, 244 int io_buffer_size, 245 const net::CompletionCallback& callback) { 246 if (socket_mode_ != CLIENT) 247 return net::ERR_FAILED; 248 else if (!socket_.get() || !IsConnected()) 249 return net::ERR_SOCKET_NOT_CONNECTED; 250 else 251 return socket_->Write(io_buffer, io_buffer_size, callback); 252 } 253 254 void TCPSocket::RefreshConnectionStatus() { 255 if (!is_connected_) return; 256 if (server_socket_) return; 257 if (!socket_->IsConnected()) { 258 is_connected_ = false; 259 socket_->Disconnect(); 260 } 261 } 262 263 void TCPSocket::OnConnectComplete(int result) { 264 DCHECK(!connect_callback_.is_null()); 265 DCHECK(!is_connected_); 266 is_connected_ = result == net::OK; 267 connect_callback_.Run(result); 268 connect_callback_.Reset(); 269 } 270 271 void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer, 272 int result) { 273 DCHECK(!read_callback_.is_null()); 274 read_callback_.Run(result, io_buffer); 275 read_callback_.Reset(); 276 } 277 278 void TCPSocket::OnAccept(int result) { 279 DCHECK(!accept_callback_.is_null()); 280 if (result == net::OK && accept_socket_.get()) { 281 accept_callback_.Run( 282 result, static_cast<net::TCPClientSocket*>(accept_socket_.release())); 283 } else { 284 accept_callback_.Run(result, NULL); 285 } 286 accept_callback_.Reset(); 287 } 288 289 } // namespace extensions 290