Fix search results being clipped in app list.
[chromium-blink-merge.git] / extensions / browser / api / socket / tcp_socket.cc
blob4863602a18b9eb2ec7fcda79e09076db4bc1871e
1 // Copyright 2014 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.
5 #include "extensions/browser/api/socket/tcp_socket.h"
7 #include "base/lazy_instance.h"
8 #include "base/logging.h"
9 #include "base/macros.h"
10 #include "extensions/browser/api/api_resource.h"
11 #include "net/base/address_list.h"
12 #include "net/base/ip_endpoint.h"
13 #include "net/base/net_errors.h"
14 #include "net/base/rand_callback.h"
15 #include "net/socket/tcp_client_socket.h"
17 namespace extensions {
19 const char kTCPSocketTypeInvalidError[] =
20 "Cannot call both connect and listen on the same socket.";
21 const char kSocketListenError[] = "Could not listen on the specified port.";
23 static base::LazyInstance<
24 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableTCPSocket> > >
25 g_factory = LAZY_INSTANCE_INITIALIZER;
27 // static
28 template <>
29 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableTCPSocket> >*
30 ApiResourceManager<ResumableTCPSocket>::GetFactoryInstance() {
31 return g_factory.Pointer();
34 static base::LazyInstance<BrowserContextKeyedAPIFactory<
35 ApiResourceManager<ResumableTCPServerSocket> > > g_server_factory =
36 LAZY_INSTANCE_INITIALIZER;
38 // static
39 template <>
40 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableTCPServerSocket> >*
41 ApiResourceManager<ResumableTCPServerSocket>::GetFactoryInstance() {
42 return g_server_factory.Pointer();
45 TCPSocket::TCPSocket(const std::string& owner_extension_id)
46 : Socket(owner_extension_id), socket_mode_(UNKNOWN) {}
48 TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket,
49 const std::string& owner_extension_id,
50 bool is_connected)
51 : Socket(owner_extension_id),
52 socket_(tcp_client_socket),
53 socket_mode_(CLIENT) {
54 this->is_connected_ = is_connected;
57 TCPSocket::TCPSocket(net::TCPServerSocket* tcp_server_socket,
58 const std::string& owner_extension_id)
59 : Socket(owner_extension_id),
60 server_socket_(tcp_server_socket),
61 socket_mode_(SERVER) {}
63 // static
64 TCPSocket* TCPSocket::CreateSocketForTesting(
65 net::TCPClientSocket* tcp_client_socket,
66 const std::string& owner_extension_id,
67 bool is_connected) {
68 return new TCPSocket(tcp_client_socket, owner_extension_id, is_connected);
71 // static
72 TCPSocket* TCPSocket::CreateServerSocketForTesting(
73 net::TCPServerSocket* tcp_server_socket,
74 const std::string& owner_extension_id) {
75 return new TCPSocket(tcp_server_socket, owner_extension_id);
78 TCPSocket::~TCPSocket() { Disconnect(); }
80 void TCPSocket::Connect(const std::string& address,
81 uint16 port,
82 const CompletionCallback& callback) {
83 DCHECK(!callback.is_null());
85 if (socket_mode_ == SERVER || !connect_callback_.is_null()) {
86 callback.Run(net::ERR_CONNECTION_FAILED);
87 return;
89 DCHECK(!server_socket_.get());
90 socket_mode_ = CLIENT;
91 connect_callback_ = callback;
93 int result = net::ERR_CONNECTION_FAILED;
94 do {
95 if (is_connected_)
96 break;
98 net::AddressList address_list;
99 if (!StringAndPortToAddressList(address, port, &address_list)) {
100 result = net::ERR_ADDRESS_INVALID;
101 break;
104 socket_.reset(
105 new net::TCPClientSocket(address_list, NULL, net::NetLog::Source()));
107 connect_callback_ = callback;
108 result = socket_->Connect(
109 base::Bind(&TCPSocket::OnConnectComplete, base::Unretained(this)));
110 } while (false);
112 if (result != net::ERR_IO_PENDING)
113 OnConnectComplete(result);
116 void TCPSocket::Disconnect() {
117 is_connected_ = false;
118 if (socket_.get())
119 socket_->Disconnect();
120 server_socket_.reset(NULL);
121 connect_callback_.Reset();
122 read_callback_.Reset();
123 accept_callback_.Reset();
124 accept_socket_.reset(NULL);
127 int TCPSocket::Bind(const std::string& address, uint16 port) {
128 return net::ERR_FAILED;
131 void TCPSocket::Read(int count, const ReadCompletionCallback& callback) {
132 DCHECK(!callback.is_null());
134 if (socket_mode_ != CLIENT) {
135 callback.Run(net::ERR_FAILED, NULL);
136 return;
139 if (!read_callback_.is_null()) {
140 callback.Run(net::ERR_IO_PENDING, NULL);
141 return;
144 if (count < 0) {
145 callback.Run(net::ERR_INVALID_ARGUMENT, NULL);
146 return;
149 if (!socket_.get() || !IsConnected()) {
150 callback.Run(net::ERR_SOCKET_NOT_CONNECTED, NULL);
151 return;
154 read_callback_ = callback;
155 scoped_refptr<net::IOBuffer> io_buffer = new net::IOBuffer(count);
156 int result = socket_->Read(
157 io_buffer.get(),
158 count,
159 base::Bind(
160 &TCPSocket::OnReadComplete, base::Unretained(this), io_buffer));
162 if (result != net::ERR_IO_PENDING)
163 OnReadComplete(io_buffer, result);
166 void TCPSocket::RecvFrom(int count,
167 const RecvFromCompletionCallback& callback) {
168 callback.Run(net::ERR_FAILED, NULL, NULL, 0);
171 void TCPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer,
172 int byte_count,
173 const std::string& address,
174 uint16 port,
175 const CompletionCallback& callback) {
176 callback.Run(net::ERR_FAILED);
179 bool TCPSocket::SetKeepAlive(bool enable, int delay) {
180 if (!socket_.get())
181 return false;
182 return socket_->SetKeepAlive(enable, delay);
185 bool TCPSocket::SetNoDelay(bool no_delay) {
186 if (!socket_.get())
187 return false;
188 return socket_->SetNoDelay(no_delay);
191 int TCPSocket::Listen(const std::string& address,
192 uint16 port,
193 int backlog,
194 std::string* error_msg) {
195 if (socket_mode_ == CLIENT) {
196 *error_msg = kTCPSocketTypeInvalidError;
197 return net::ERR_NOT_IMPLEMENTED;
199 DCHECK(!socket_.get());
200 socket_mode_ = SERVER;
202 if (!server_socket_.get()) {
203 server_socket_.reset(new net::TCPServerSocket(NULL, net::NetLog::Source()));
206 int result = server_socket_->ListenWithAddressAndPort(address, port, backlog);
207 if (result)
208 *error_msg = kSocketListenError;
209 return result;
212 void TCPSocket::Accept(const AcceptCompletionCallback& callback) {
213 if (socket_mode_ != SERVER || !server_socket_.get()) {
214 callback.Run(net::ERR_FAILED, NULL);
215 return;
218 // Limits to only 1 blocked accept call.
219 if (!accept_callback_.is_null()) {
220 callback.Run(net::ERR_FAILED, NULL);
221 return;
224 int result = server_socket_->Accept(
225 &accept_socket_,
226 base::Bind(&TCPSocket::OnAccept, base::Unretained(this)));
227 if (result == net::ERR_IO_PENDING) {
228 accept_callback_ = callback;
229 } else if (result == net::OK) {
230 accept_callback_ = callback;
231 this->OnAccept(result);
232 } else {
233 callback.Run(result, NULL);
237 bool TCPSocket::IsConnected() {
238 RefreshConnectionStatus();
239 return is_connected_;
242 bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) {
243 if (!socket_.get())
244 return false;
245 return !socket_->GetPeerAddress(address);
248 bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) {
249 if (socket_.get()) {
250 return !socket_->GetLocalAddress(address);
251 } else if (server_socket_.get()) {
252 return !server_socket_->GetLocalAddress(address);
253 } else {
254 return false;
258 Socket::SocketType TCPSocket::GetSocketType() const { return Socket::TYPE_TCP; }
260 int TCPSocket::WriteImpl(net::IOBuffer* io_buffer,
261 int io_buffer_size,
262 const net::CompletionCallback& callback) {
263 if (socket_mode_ != CLIENT)
264 return net::ERR_FAILED;
265 else if (!socket_.get() || !IsConnected())
266 return net::ERR_SOCKET_NOT_CONNECTED;
267 else
268 return socket_->Write(io_buffer, io_buffer_size, callback);
271 void TCPSocket::RefreshConnectionStatus() {
272 if (!is_connected_)
273 return;
274 if (server_socket_)
275 return;
276 if (!socket_->IsConnected()) {
277 Disconnect();
281 void TCPSocket::OnConnectComplete(int result) {
282 DCHECK(!connect_callback_.is_null());
283 DCHECK(!is_connected_);
284 is_connected_ = result == net::OK;
285 connect_callback_.Run(result);
286 connect_callback_.Reset();
289 void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
290 int result) {
291 DCHECK(!read_callback_.is_null());
292 read_callback_.Run(result, io_buffer);
293 read_callback_.Reset();
296 void TCPSocket::OnAccept(int result) {
297 DCHECK(!accept_callback_.is_null());
298 if (result == net::OK && accept_socket_.get()) {
299 accept_callback_.Run(
300 result, static_cast<net::TCPClientSocket*>(accept_socket_.release()));
301 } else {
302 accept_callback_.Run(result, NULL);
304 accept_callback_.Reset();
307 void TCPSocket::Release() {
308 // Release() is only invoked when the underlying sockets are taken (via
309 // ClientStream()) by TLSSocket. TLSSocket only supports CLIENT-mode
310 // sockets.
311 DCHECK(!server_socket_.release() && !accept_socket_.release() &&
312 socket_mode_ == CLIENT)
313 << "Called in server mode.";
315 // Release() doesn't disconnect the underlying sockets, but it does
316 // disconnect them from this TCPSocket.
317 is_connected_ = false;
319 connect_callback_.Reset();
320 read_callback_.Reset();
321 accept_callback_.Reset();
323 DCHECK(socket_.get()) << "Called on null client socket.";
324 ignore_result(socket_.release());
327 net::TCPClientSocket* TCPSocket::ClientStream() {
328 if (socket_mode_ != CLIENT || GetSocketType() != TYPE_TCP)
329 return NULL;
330 return socket_.get();
333 bool TCPSocket::HasPendingRead() const {
334 return !read_callback_.is_null();
337 ResumableTCPSocket::ResumableTCPSocket(const std::string& owner_extension_id)
338 : TCPSocket(owner_extension_id),
339 persistent_(false),
340 buffer_size_(0),
341 paused_(false) {}
343 ResumableTCPSocket::ResumableTCPSocket(net::TCPClientSocket* tcp_client_socket,
344 const std::string& owner_extension_id,
345 bool is_connected)
346 : TCPSocket(tcp_client_socket, owner_extension_id, is_connected),
347 persistent_(false),
348 buffer_size_(0),
349 paused_(false) {}
351 bool ResumableTCPSocket::IsPersistent() const { return persistent(); }
353 ResumableTCPServerSocket::ResumableTCPServerSocket(
354 const std::string& owner_extension_id)
355 : TCPSocket(owner_extension_id), persistent_(false), paused_(false) {}
357 bool ResumableTCPServerSocket::IsPersistent() const { return persistent(); }
359 } // namespace extensions