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.
4
5#include "extensions/browser/api/socket/socket.h"
6
7#include "base/bind.h"
8#include "base/lazy_instance.h"
9#include "extensions/browser/api/api_resource_manager.h"
10#include "net/base/address_list.h"
11#include "net/base/io_buffer.h"
12#include "net/base/ip_endpoint.h"
13#include "net/base/net_errors.h"
14#include "net/socket/socket.h"
15
16namespace extensions {
17
18const char kSocketTypeNotSupported[] = "Socket type does not support this API";
19
20static base::LazyInstance<
21    BrowserContextKeyedAPIFactory<ApiResourceManager<Socket> > > g_factory =
22    LAZY_INSTANCE_INITIALIZER;
23
24// static
25template <>
26BrowserContextKeyedAPIFactory<ApiResourceManager<Socket> >*
27ApiResourceManager<Socket>::GetFactoryInstance() {
28  return g_factory.Pointer();
29}
30
31Socket::Socket(const std::string& owner_extension_id)
32    : ApiResource(owner_extension_id), is_connected_(false) {}
33
34Socket::~Socket() {
35  // Derived destructors should make sure the socket has been closed.
36  DCHECK(!is_connected_);
37}
38
39void Socket::Write(scoped_refptr<net::IOBuffer> io_buffer,
40                   int byte_count,
41                   const CompletionCallback& callback) {
42  DCHECK(!callback.is_null());
43  write_queue_.push(WriteRequest(io_buffer, byte_count, callback));
44  WriteData();
45}
46
47void Socket::WriteData() {
48  // IO is pending.
49  if (io_buffer_write_.get())
50    return;
51
52  WriteRequest& request = write_queue_.front();
53
54  DCHECK(request.byte_count >= request.bytes_written);
55  io_buffer_write_ = new net::WrappedIOBuffer(request.io_buffer->data() +
56                                              request.bytes_written);
57  int result =
58      WriteImpl(io_buffer_write_.get(),
59                request.byte_count - request.bytes_written,
60                base::Bind(&Socket::OnWriteComplete, base::Unretained(this)));
61
62  if (result != net::ERR_IO_PENDING)
63    OnWriteComplete(result);
64}
65
66void Socket::OnWriteComplete(int result) {
67  io_buffer_write_ = NULL;
68
69  WriteRequest& request = write_queue_.front();
70
71  if (result >= 0) {
72    request.bytes_written += result;
73    if (request.bytes_written < request.byte_count) {
74      WriteData();
75      return;
76    }
77    DCHECK(request.bytes_written == request.byte_count);
78    result = request.bytes_written;
79  }
80
81  request.callback.Run(result);
82  write_queue_.pop();
83
84  if (!write_queue_.empty())
85    WriteData();
86}
87
88bool Socket::SetKeepAlive(bool enable, int delay) { return false; }
89
90bool Socket::SetNoDelay(bool no_delay) { return false; }
91
92int Socket::Listen(const std::string& address,
93                   int port,
94                   int backlog,
95                   std::string* error_msg) {
96  *error_msg = kSocketTypeNotSupported;
97  return net::ERR_FAILED;
98}
99
100void Socket::Accept(const AcceptCompletionCallback& callback) {
101  callback.Run(net::ERR_FAILED, NULL);
102}
103
104// static
105bool Socket::StringAndPortToIPEndPoint(const std::string& ip_address_str,
106                                       int port,
107                                       net::IPEndPoint* ip_end_point) {
108  DCHECK(ip_end_point);
109  net::IPAddressNumber ip_number;
110  if (!net::ParseIPLiteralToNumber(ip_address_str, &ip_number))
111    return false;
112
113  *ip_end_point = net::IPEndPoint(ip_number, port);
114  return true;
115}
116
117bool Socket::StringAndPortToAddressList(const std::string& ip_address_str,
118                                        int port,
119                                        net::AddressList* address_list) {
120  DCHECK(address_list);
121  net::IPAddressNumber ip_number;
122  if (!net::ParseIPLiteralToNumber(ip_address_str, &ip_number))
123    return false;
124
125  *address_list = net::AddressList::CreateFromIPAddress(ip_number, port);
126  return true;
127}
128
129void Socket::IPEndPointToStringAndPort(const net::IPEndPoint& address,
130                                       std::string* ip_address_str,
131                                       int* port) {
132  DCHECK(ip_address_str);
133  DCHECK(port);
134  *ip_address_str = address.ToStringWithoutPort();
135  if (ip_address_str->empty()) {
136    *port = 0;
137  } else {
138    *port = address.port();
139  }
140}
141
142Socket::WriteRequest::WriteRequest(scoped_refptr<net::IOBuffer> io_buffer,
143                                   int byte_count,
144                                   const CompletionCallback& callback)
145    : io_buffer(io_buffer),
146      byte_count(byte_count),
147      callback(callback),
148      bytes_written(0) {}
149
150Socket::WriteRequest::~WriteRequest() {}
151
152}  // namespace extensions
153