| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "extensions/browser/api/socket/socket.h" |
| |
| #include "base/bind.h" |
| #include "base/lazy_instance.h" |
| #include "extensions/browser/api/api_resource_manager.h" |
| #include "net/base/address_list.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/ip_address.h" |
| #include "net/base/ip_endpoint.h" |
| #include "net/base/net_errors.h" |
| #include "net/socket/socket.h" |
| |
| namespace extensions { |
| |
| const char kSocketTypeNotSupported[] = "Socket type does not support this API"; |
| |
| static base::LazyInstance< |
| BrowserContextKeyedAPIFactory<ApiResourceManager<Socket>>>::DestructorAtExit |
| g_factory = LAZY_INSTANCE_INITIALIZER; |
| |
| // static |
| template <> |
| BrowserContextKeyedAPIFactory<ApiResourceManager<Socket> >* |
| ApiResourceManager<Socket>::GetFactoryInstance() { |
| return g_factory.Pointer(); |
| } |
| |
| Socket::Socket(const std::string& owner_extension_id) |
| : ApiResource(owner_extension_id), is_connected_(false) {} |
| |
| Socket::~Socket() { |
| // Derived destructors should make sure the socket has been closed. |
| DCHECK(!is_connected_); |
| } |
| |
| void Socket::Write(scoped_refptr<net::IOBuffer> io_buffer, |
| int byte_count, |
| const CompletionCallback& callback) { |
| DCHECK(!callback.is_null()); |
| write_queue_.push(WriteRequest(io_buffer, byte_count, callback)); |
| WriteData(); |
| } |
| |
| void Socket::WriteData() { |
| // IO is pending. |
| if (io_buffer_write_.get()) |
| return; |
| |
| WriteRequest& request = write_queue_.front(); |
| |
| DCHECK(request.byte_count >= request.bytes_written); |
| io_buffer_write_ = new net::WrappedIOBuffer(request.io_buffer->data() + |
| request.bytes_written); |
| int result = |
| WriteImpl(io_buffer_write_.get(), |
| request.byte_count - request.bytes_written, |
| base::Bind(&Socket::OnWriteComplete, base::Unretained(this))); |
| |
| if (result != net::ERR_IO_PENDING) |
| OnWriteComplete(result); |
| } |
| |
| void Socket::OnWriteComplete(int result) { |
| io_buffer_write_ = NULL; |
| |
| WriteRequest& request = write_queue_.front(); |
| |
| if (result >= 0) { |
| request.bytes_written += result; |
| if (request.bytes_written < request.byte_count) { |
| WriteData(); |
| return; |
| } |
| DCHECK(request.bytes_written == request.byte_count); |
| result = request.bytes_written; |
| } |
| |
| request.callback.Run(result); |
| write_queue_.pop(); |
| |
| if (!write_queue_.empty()) |
| WriteData(); |
| } |
| |
| bool Socket::SetKeepAlive(bool enable, int delay) { return false; } |
| |
| bool Socket::SetNoDelay(bool no_delay) { return false; } |
| |
| int Socket::Listen(const std::string& address, |
| uint16_t port, |
| int backlog, |
| std::string* error_msg) { |
| *error_msg = kSocketTypeNotSupported; |
| return net::ERR_FAILED; |
| } |
| |
| void Socket::Accept(const AcceptCompletionCallback& callback) { |
| callback.Run(net::ERR_FAILED, NULL); |
| } |
| |
| // static |
| bool Socket::StringAndPortToIPEndPoint(const std::string& ip_address_str, |
| uint16_t port, |
| net::IPEndPoint* ip_end_point) { |
| DCHECK(ip_end_point); |
| net::IPAddress ip_address; |
| if (!ip_address.AssignFromIPLiteral(ip_address_str)) |
| return false; |
| |
| *ip_end_point = net::IPEndPoint(ip_address, port); |
| return true; |
| } |
| |
| void Socket::IPEndPointToStringAndPort(const net::IPEndPoint& address, |
| std::string* ip_address_str, |
| uint16_t* port) { |
| DCHECK(ip_address_str); |
| DCHECK(port); |
| *ip_address_str = address.ToStringWithoutPort(); |
| if (ip_address_str->empty()) { |
| *port = 0; |
| } else { |
| *port = address.port(); |
| } |
| } |
| |
| Socket::WriteRequest::WriteRequest(scoped_refptr<net::IOBuffer> io_buffer, |
| int byte_count, |
| const CompletionCallback& callback) |
| : io_buffer(io_buffer), |
| byte_count(byte_count), |
| callback(callback), |
| bytes_written(0) {} |
| |
| Socket::WriteRequest::WriteRequest(const WriteRequest& other) = default; |
| |
| Socket::WriteRequest::~WriteRequest() {} |
| |
| } // namespace extensions |