Add ICU message format support
[chromium-blink-merge.git] / extensions / browser / api / socket / tcp_socket.cc
blob8d5257b45c3007ba9e7c0bb2bde5dc6efb2792f6
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 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);
86 return;
88 DCHECK(!server_socket_.get());
89 socket_mode_ = CLIENT;
90 connect_callback_ = callback;
92 int result = net::ERR_CONNECTION_FAILED;
93 do {
94 if (is_connected_)
95 break;
97 socket_.reset(
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)));
103 } while (false);
105 if (result != net::ERR_IO_PENDING)
106 OnConnectComplete(result);
109 void TCPSocket::Disconnect() {
110 is_connected_ = false;
111 if (socket_.get())
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);
129 return;
132 if (!read_callback_.is_null()) {
133 callback.Run(net::ERR_IO_PENDING, NULL);
134 return;
137 if (count < 0) {
138 callback.Run(net::ERR_INVALID_ARGUMENT, NULL);
139 return;
142 if (!socket_.get() || !IsConnected()) {
143 callback.Run(net::ERR_SOCKET_NOT_CONNECTED, NULL);
144 return;
147 read_callback_ = callback;
148 scoped_refptr<net::IOBuffer> io_buffer = new net::IOBuffer(count);
149 int result = socket_->Read(
150 io_buffer.get(),
151 count,
152 base::Bind(
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,
165 int byte_count,
166 const net::IPEndPoint& address,
167 const CompletionCallback& callback) {
168 callback.Run(net::ERR_FAILED);
171 bool TCPSocket::SetKeepAlive(bool enable, int delay) {
172 if (!socket_.get())
173 return false;
174 return socket_->SetKeepAlive(enable, delay);
177 bool TCPSocket::SetNoDelay(bool no_delay) {
178 if (!socket_.get())
179 return false;
180 return socket_->SetNoDelay(no_delay);
183 int TCPSocket::Listen(const std::string& address,
184 uint16 port,
185 int backlog,
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);
199 if (result)
200 *error_msg = kSocketListenError;
201 return result;
204 void TCPSocket::Accept(const AcceptCompletionCallback& callback) {
205 if (socket_mode_ != SERVER || !server_socket_.get()) {
206 callback.Run(net::ERR_FAILED, NULL);
207 return;
210 // Limits to only 1 blocked accept call.
211 if (!accept_callback_.is_null()) {
212 callback.Run(net::ERR_FAILED, NULL);
213 return;
216 int result = server_socket_->Accept(
217 &accept_socket_,
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);
224 } else {
225 callback.Run(result, NULL);
229 bool TCPSocket::IsConnected() {
230 RefreshConnectionStatus();
231 return is_connected_;
234 bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) {
235 if (!socket_.get())
236 return false;
237 return !socket_->GetPeerAddress(address);
240 bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) {
241 if (socket_.get()) {
242 return !socket_->GetLocalAddress(address);
243 } else if (server_socket_.get()) {
244 return !server_socket_->GetLocalAddress(address);
245 } else {
246 return false;
250 Socket::SocketType TCPSocket::GetSocketType() const { return Socket::TYPE_TCP; }
252 int TCPSocket::WriteImpl(net::IOBuffer* io_buffer,
253 int io_buffer_size,
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;
259 else
260 return socket_->Write(io_buffer, io_buffer_size, callback);
263 void TCPSocket::RefreshConnectionStatus() {
264 if (!is_connected_)
265 return;
266 if (server_socket_)
267 return;
268 if (!socket_->IsConnected()) {
269 Disconnect();
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,
282 int result) {
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()));
293 } else {
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
302 // sockets.
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)
321 return NULL;
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),
331 persistent_(false),
332 buffer_size_(0),
333 paused_(false) {}
335 ResumableTCPSocket::ResumableTCPSocket(net::TCPClientSocket* tcp_client_socket,
336 const std::string& owner_extension_id,
337 bool is_connected)
338 : TCPSocket(tcp_client_socket, owner_extension_id, is_connected),
339 persistent_(false),
340 buffer_size_(0),
341 paused_(false) {}
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