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 net::AddressList
& address
,
81 const CompletionCallback
& callback
) {
82 DCHECK(!callback
.is_null());
84 if (socket_mode_
== SERVER
|| !connect_callback_
.is_null()) {
85 callback
.Run(net::ERR_CONNECTION_FAILED
);
88 DCHECK(!server_socket_
.get());
89 socket_mode_
= CLIENT
;
90 connect_callback_
= callback
;
92 int result
= net::ERR_CONNECTION_FAILED
;
98 new net::TCPClientSocket(address
, NULL
, net::NetLog::Source()));
100 connect_callback_
= callback
;
101 result
= socket_
->Connect(
102 base::Bind(&TCPSocket::OnConnectComplete
, base::Unretained(this)));
105 if (result
!= net::ERR_IO_PENDING
)
106 OnConnectComplete(result
);
109 void TCPSocket::Disconnect() {
110 is_connected_
= false;
112 socket_
->Disconnect();
113 server_socket_
.reset(NULL
);
114 connect_callback_
.Reset();
115 read_callback_
.Reset();
116 accept_callback_
.Reset();
117 accept_socket_
.reset(NULL
);
120 int TCPSocket::Bind(const std::string
& address
, uint16 port
) {
121 return net::ERR_FAILED
;
124 void TCPSocket::Read(int count
, const ReadCompletionCallback
& callback
) {
125 DCHECK(!callback
.is_null());
127 if (socket_mode_
!= CLIENT
) {
128 callback
.Run(net::ERR_FAILED
, NULL
);
132 if (!read_callback_
.is_null()) {
133 callback
.Run(net::ERR_IO_PENDING
, NULL
);
138 callback
.Run(net::ERR_INVALID_ARGUMENT
, NULL
);
142 if (!socket_
.get() || !IsConnected()) {
143 callback
.Run(net::ERR_SOCKET_NOT_CONNECTED
, NULL
);
147 read_callback_
= callback
;
148 scoped_refptr
<net::IOBuffer
> io_buffer
= new net::IOBuffer(count
);
149 int result
= socket_
->Read(
153 &TCPSocket::OnReadComplete
, base::Unretained(this), io_buffer
));
155 if (result
!= net::ERR_IO_PENDING
)
156 OnReadComplete(io_buffer
, result
);
159 void TCPSocket::RecvFrom(int count
,
160 const RecvFromCompletionCallback
& callback
) {
161 callback
.Run(net::ERR_FAILED
, NULL
, NULL
, 0);
164 void TCPSocket::SendTo(scoped_refptr
<net::IOBuffer
> io_buffer
,
166 const net::IPEndPoint
& address
,
167 const CompletionCallback
& callback
) {
168 callback
.Run(net::ERR_FAILED
);
171 bool TCPSocket::SetKeepAlive(bool enable
, int delay
) {
174 return socket_
->SetKeepAlive(enable
, delay
);
177 bool TCPSocket::SetNoDelay(bool no_delay
) {
180 return socket_
->SetNoDelay(no_delay
);
183 int TCPSocket::Listen(const std::string
& address
,
186 std::string
* error_msg
) {
187 if (socket_mode_
== CLIENT
) {
188 *error_msg
= kTCPSocketTypeInvalidError
;
189 return net::ERR_NOT_IMPLEMENTED
;
191 DCHECK(!socket_
.get());
192 socket_mode_
= SERVER
;
194 if (!server_socket_
.get()) {
195 server_socket_
.reset(new net::TCPServerSocket(NULL
, net::NetLog::Source()));
198 int result
= server_socket_
->ListenWithAddressAndPort(address
, port
, backlog
);
200 *error_msg
= kSocketListenError
;
204 void TCPSocket::Accept(const AcceptCompletionCallback
& callback
) {
205 if (socket_mode_
!= SERVER
|| !server_socket_
.get()) {
206 callback
.Run(net::ERR_FAILED
, NULL
);
210 // Limits to only 1 blocked accept call.
211 if (!accept_callback_
.is_null()) {
212 callback
.Run(net::ERR_FAILED
, NULL
);
216 int result
= server_socket_
->Accept(
218 base::Bind(&TCPSocket::OnAccept
, base::Unretained(this)));
219 if (result
== net::ERR_IO_PENDING
) {
220 accept_callback_
= callback
;
221 } else if (result
== net::OK
) {
222 accept_callback_
= callback
;
223 this->OnAccept(result
);
225 callback
.Run(result
, NULL
);
229 bool TCPSocket::IsConnected() {
230 RefreshConnectionStatus();
231 return is_connected_
;
234 bool TCPSocket::GetPeerAddress(net::IPEndPoint
* address
) {
237 return !socket_
->GetPeerAddress(address
);
240 bool TCPSocket::GetLocalAddress(net::IPEndPoint
* address
) {
242 return !socket_
->GetLocalAddress(address
);
243 } else if (server_socket_
.get()) {
244 return !server_socket_
->GetLocalAddress(address
);
250 Socket::SocketType
TCPSocket::GetSocketType() const { return Socket::TYPE_TCP
; }
252 int TCPSocket::WriteImpl(net::IOBuffer
* io_buffer
,
254 const net::CompletionCallback
& callback
) {
255 if (socket_mode_
!= CLIENT
)
256 return net::ERR_FAILED
;
257 else if (!socket_
.get() || !IsConnected())
258 return net::ERR_SOCKET_NOT_CONNECTED
;
260 return socket_
->Write(io_buffer
, io_buffer_size
, callback
);
263 void TCPSocket::RefreshConnectionStatus() {
268 if (!socket_
->IsConnected()) {
273 void TCPSocket::OnConnectComplete(int result
) {
274 DCHECK(!connect_callback_
.is_null());
275 DCHECK(!is_connected_
);
276 is_connected_
= result
== net::OK
;
277 connect_callback_
.Run(result
);
278 connect_callback_
.Reset();
281 void TCPSocket::OnReadComplete(scoped_refptr
<net::IOBuffer
> io_buffer
,
283 DCHECK(!read_callback_
.is_null());
284 read_callback_
.Run(result
, io_buffer
);
285 read_callback_
.Reset();
288 void TCPSocket::OnAccept(int result
) {
289 DCHECK(!accept_callback_
.is_null());
290 if (result
== net::OK
&& accept_socket_
.get()) {
291 accept_callback_
.Run(
292 result
, static_cast<net::TCPClientSocket
*>(accept_socket_
.release()));
294 accept_callback_
.Run(result
, NULL
);
296 accept_callback_
.Reset();
299 void TCPSocket::Release() {
300 // Release() is only invoked when the underlying sockets are taken (via
301 // ClientStream()) by TLSSocket. TLSSocket only supports CLIENT-mode
303 DCHECK(!server_socket_
.release() && !accept_socket_
.release() &&
304 socket_mode_
== CLIENT
)
305 << "Called in server mode.";
307 // Release() doesn't disconnect the underlying sockets, but it does
308 // disconnect them from this TCPSocket.
309 is_connected_
= false;
311 connect_callback_
.Reset();
312 read_callback_
.Reset();
313 accept_callback_
.Reset();
315 DCHECK(socket_
.get()) << "Called on null client socket.";
316 ignore_result(socket_
.release());
319 net::TCPClientSocket
* TCPSocket::ClientStream() {
320 if (socket_mode_
!= CLIENT
|| GetSocketType() != TYPE_TCP
)
322 return socket_
.get();
325 bool TCPSocket::HasPendingRead() const {
326 return !read_callback_
.is_null();
329 ResumableTCPSocket::ResumableTCPSocket(const std::string
& owner_extension_id
)
330 : TCPSocket(owner_extension_id
),
335 ResumableTCPSocket::ResumableTCPSocket(net::TCPClientSocket
* tcp_client_socket
,
336 const std::string
& owner_extension_id
,
338 : TCPSocket(tcp_client_socket
, owner_extension_id
, is_connected
),
343 bool ResumableTCPSocket::IsPersistent() const { return persistent(); }
345 ResumableTCPServerSocket::ResumableTCPServerSocket(
346 const std::string
& owner_extension_id
)
347 : TCPSocket(owner_extension_id
), persistent_(false), paused_(false) {}
349 bool ResumableTCPServerSocket::IsPersistent() const { return persistent(); }
351 } // namespace extensions