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
;
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
;
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
,
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
) {}
64 TCPSocket
* TCPSocket::CreateSocketForTesting(
65 net::TCPClientSocket
* tcp_client_socket
,
66 const std::string
& owner_extension_id
,
68 return new TCPSocket(tcp_client_socket
, owner_extension_id
, is_connected
);
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
,
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
);
89 DCHECK(!server_socket_
.get());
90 socket_mode_
= CLIENT
;
91 connect_callback_
= callback
;
93 int result
= net::ERR_CONNECTION_FAILED
;
98 net::AddressList address_list
;
99 if (!StringAndPortToAddressList(address
, port
, &address_list
)) {
100 result
= net::ERR_ADDRESS_INVALID
;
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)));
112 if (result
!= net::ERR_IO_PENDING
)
113 OnConnectComplete(result
);
116 void TCPSocket::Disconnect() {
117 is_connected_
= false;
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
);
139 if (!read_callback_
.is_null()) {
140 callback
.Run(net::ERR_IO_PENDING
, NULL
);
145 callback
.Run(net::ERR_INVALID_ARGUMENT
, NULL
);
149 if (!socket_
.get() || !IsConnected()) {
150 callback
.Run(net::ERR_SOCKET_NOT_CONNECTED
, NULL
);
154 read_callback_
= callback
;
155 scoped_refptr
<net::IOBuffer
> io_buffer
= new net::IOBuffer(count
);
156 int result
= socket_
->Read(
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
,
173 const std::string
& address
,
175 const CompletionCallback
& callback
) {
176 callback
.Run(net::ERR_FAILED
);
179 bool TCPSocket::SetKeepAlive(bool enable
, int delay
) {
182 return socket_
->SetKeepAlive(enable
, delay
);
185 bool TCPSocket::SetNoDelay(bool no_delay
) {
188 return socket_
->SetNoDelay(no_delay
);
191 int TCPSocket::Listen(const std::string
& address
,
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
);
208 *error_msg
= kSocketListenError
;
212 void TCPSocket::Accept(const AcceptCompletionCallback
& callback
) {
213 if (socket_mode_
!= SERVER
|| !server_socket_
.get()) {
214 callback
.Run(net::ERR_FAILED
, NULL
);
218 // Limits to only 1 blocked accept call.
219 if (!accept_callback_
.is_null()) {
220 callback
.Run(net::ERR_FAILED
, NULL
);
224 int result
= server_socket_
->Accept(
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
);
233 callback
.Run(result
, NULL
);
237 bool TCPSocket::IsConnected() {
238 RefreshConnectionStatus();
239 return is_connected_
;
242 bool TCPSocket::GetPeerAddress(net::IPEndPoint
* address
) {
245 return !socket_
->GetPeerAddress(address
);
248 bool TCPSocket::GetLocalAddress(net::IPEndPoint
* address
) {
250 return !socket_
->GetLocalAddress(address
);
251 } else if (server_socket_
.get()) {
252 return !server_socket_
->GetLocalAddress(address
);
258 Socket::SocketType
TCPSocket::GetSocketType() const { return Socket::TYPE_TCP
; }
260 int TCPSocket::WriteImpl(net::IOBuffer
* io_buffer
,
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
;
268 return socket_
->Write(io_buffer
, io_buffer_size
, callback
);
271 void TCPSocket::RefreshConnectionStatus() {
276 if (!socket_
->IsConnected()) {
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
,
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()));
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
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
)
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
),
343 ResumableTCPSocket::ResumableTCPSocket(net::TCPClientSocket
* tcp_client_socket
,
344 const std::string
& owner_extension_id
,
346 : TCPSocket(tcp_client_socket
, owner_extension_id
, is_connected
),
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