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/sockets_tcp_server/sockets_tcp_server_api.h"
6
7#include "content/public/common/socket_permission_request.h"
8#include "extensions/browser/api/socket/tcp_socket.h"
9#include "extensions/browser/api/sockets_tcp_server/tcp_server_socket_event_dispatcher.h"
10#include "extensions/common/api/sockets/sockets_manifest_data.h"
11#include "extensions/common/permissions/permissions_data.h"
12#include "extensions/common/permissions/socket_permission.h"
13#include "net/base/net_errors.h"
14
15using content::SocketPermissionRequest;
16using extensions::ResumableTCPServerSocket;
17using extensions::core_api::sockets_tcp_server::SocketInfo;
18using extensions::core_api::sockets_tcp_server::SocketProperties;
19
20namespace {
21
22const char kSocketNotFoundError[] = "Socket not found";
23const char kPermissionError[] = "Does not have permission";
24const int kDefaultListenBacklog = SOMAXCONN;
25
26linked_ptr<SocketInfo> CreateSocketInfo(int socket_id,
27                                        ResumableTCPServerSocket* socket) {
28  linked_ptr<SocketInfo> socket_info(new SocketInfo());
29  // This represents what we know about the socket, and does not call through
30  // to the system.
31  socket_info->socket_id = socket_id;
32  if (!socket->name().empty()) {
33    socket_info->name.reset(new std::string(socket->name()));
34  }
35  socket_info->persistent = socket->persistent();
36  socket_info->paused = socket->paused();
37
38  // Grab the local address as known by the OS.
39  net::IPEndPoint localAddress;
40  if (socket->GetLocalAddress(&localAddress)) {
41    socket_info->local_address.reset(
42        new std::string(localAddress.ToStringWithoutPort()));
43    socket_info->local_port.reset(new int(localAddress.port()));
44  }
45
46  return socket_info;
47}
48
49void SetSocketProperties(ResumableTCPServerSocket* socket,
50                         SocketProperties* properties) {
51  if (properties->name.get()) {
52    socket->set_name(*properties->name.get());
53  }
54  if (properties->persistent.get()) {
55    socket->set_persistent(*properties->persistent.get());
56  }
57}
58
59}  // namespace
60
61namespace extensions {
62namespace core_api {
63
64TCPServerSocketAsyncApiFunction::~TCPServerSocketAsyncApiFunction() {}
65
66scoped_ptr<SocketResourceManagerInterface>
67TCPServerSocketAsyncApiFunction::CreateSocketResourceManager() {
68  return scoped_ptr<SocketResourceManagerInterface>(
69             new SocketResourceManager<ResumableTCPServerSocket>()).Pass();
70}
71
72ResumableTCPServerSocket* TCPServerSocketAsyncApiFunction::GetTcpSocket(
73    int socket_id) {
74  return static_cast<ResumableTCPServerSocket*>(GetSocket(socket_id));
75}
76
77SocketsTcpServerCreateFunction::SocketsTcpServerCreateFunction() {}
78
79SocketsTcpServerCreateFunction::~SocketsTcpServerCreateFunction() {}
80
81bool SocketsTcpServerCreateFunction::Prepare() {
82  params_ = sockets_tcp_server::Create::Params::Create(*args_);
83  EXTENSION_FUNCTION_VALIDATE(params_.get());
84  return true;
85}
86
87void SocketsTcpServerCreateFunction::Work() {
88  ResumableTCPServerSocket* socket =
89      new ResumableTCPServerSocket(extension_->id());
90
91  sockets_tcp_server::SocketProperties* properties =
92      params_.get()->properties.get();
93  if (properties) {
94    SetSocketProperties(socket, properties);
95  }
96
97  sockets_tcp_server::CreateInfo create_info;
98  create_info.socket_id = AddSocket(socket);
99  results_ = sockets_tcp_server::Create::Results::Create(create_info);
100}
101
102SocketsTcpServerUpdateFunction::SocketsTcpServerUpdateFunction() {}
103
104SocketsTcpServerUpdateFunction::~SocketsTcpServerUpdateFunction() {}
105
106bool SocketsTcpServerUpdateFunction::Prepare() {
107  params_ = sockets_tcp_server::Update::Params::Create(*args_);
108  EXTENSION_FUNCTION_VALIDATE(params_.get());
109  return true;
110}
111
112void SocketsTcpServerUpdateFunction::Work() {
113  ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
114  if (!socket) {
115    error_ = kSocketNotFoundError;
116    return;
117  }
118
119  SetSocketProperties(socket, &params_.get()->properties);
120  results_ = sockets_tcp_server::Update::Results::Create();
121}
122
123SocketsTcpServerSetPausedFunction::SocketsTcpServerSetPausedFunction()
124    : socket_event_dispatcher_(NULL) {}
125
126SocketsTcpServerSetPausedFunction::~SocketsTcpServerSetPausedFunction() {}
127
128bool SocketsTcpServerSetPausedFunction::Prepare() {
129  params_ = core_api::sockets_tcp_server::SetPaused::Params::Create(*args_);
130  EXTENSION_FUNCTION_VALIDATE(params_.get());
131
132  socket_event_dispatcher_ =
133      TCPServerSocketEventDispatcher::Get(browser_context());
134  DCHECK(socket_event_dispatcher_)
135      << "There is no socket event dispatcher. "
136         "If this assertion is failing during a test, then it is likely that "
137         "TestExtensionSystem is failing to provide an instance of "
138         "TCPServerSocketEventDispatcher.";
139  return socket_event_dispatcher_ != NULL;
140}
141
142void SocketsTcpServerSetPausedFunction::Work() {
143  ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
144  if (!socket) {
145    error_ = kSocketNotFoundError;
146    return;
147  }
148
149  if (socket->paused() != params_->paused) {
150    socket->set_paused(params_->paused);
151    if (socket->IsConnected() && !params_->paused) {
152      socket_event_dispatcher_->OnServerSocketResume(extension_->id(),
153                                                     params_->socket_id);
154    }
155  }
156
157  results_ = sockets_tcp_server::SetPaused::Results::Create();
158}
159
160SocketsTcpServerListenFunction::SocketsTcpServerListenFunction()
161    : socket_event_dispatcher_(NULL) {}
162
163SocketsTcpServerListenFunction::~SocketsTcpServerListenFunction() {}
164
165bool SocketsTcpServerListenFunction::Prepare() {
166  params_ = core_api::sockets_tcp_server::Listen::Params::Create(*args_);
167  EXTENSION_FUNCTION_VALIDATE(params_.get());
168
169  socket_event_dispatcher_ =
170      TCPServerSocketEventDispatcher::Get(browser_context());
171  DCHECK(socket_event_dispatcher_)
172      << "There is no socket event dispatcher. "
173         "If this assertion is failing during a test, then it is likely that "
174         "TestExtensionSystem is failing to provide an instance of "
175         "TCPServerSocketEventDispatcher.";
176  return socket_event_dispatcher_ != NULL;
177}
178
179void SocketsTcpServerListenFunction::Work() {
180  ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
181  if (!socket) {
182    error_ = kSocketNotFoundError;
183    return;
184  }
185
186  SocketPermissionRequest param(
187      SocketPermissionRequest::TCP_LISTEN, params_->address, params_->port);
188  if (!SocketsManifestData::CheckRequest(extension(), param)) {
189    error_ = kPermissionError;
190    return;
191  }
192
193  int net_result = socket->Listen(
194      params_->address,
195      params_->port,
196      params_->backlog.get() ? *params_->backlog.get() : kDefaultListenBacklog,
197      &error_);
198
199  if (net_result != net::OK)
200    error_ = net::ErrorToString(net_result);
201
202  if (net_result == net::OK) {
203    socket_event_dispatcher_->OnServerSocketListen(extension_->id(),
204                                                   params_->socket_id);
205  }
206
207  results_ = sockets_tcp_server::Listen::Results::Create(net_result);
208}
209
210SocketsTcpServerDisconnectFunction::SocketsTcpServerDisconnectFunction() {}
211
212SocketsTcpServerDisconnectFunction::~SocketsTcpServerDisconnectFunction() {}
213
214bool SocketsTcpServerDisconnectFunction::Prepare() {
215  params_ = sockets_tcp_server::Disconnect::Params::Create(*args_);
216  EXTENSION_FUNCTION_VALIDATE(params_.get());
217  return true;
218}
219
220void SocketsTcpServerDisconnectFunction::Work() {
221  ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
222  if (!socket) {
223    error_ = kSocketNotFoundError;
224    return;
225  }
226
227  socket->Disconnect();
228  results_ = sockets_tcp_server::Disconnect::Results::Create();
229}
230
231SocketsTcpServerCloseFunction::SocketsTcpServerCloseFunction() {}
232
233SocketsTcpServerCloseFunction::~SocketsTcpServerCloseFunction() {}
234
235bool SocketsTcpServerCloseFunction::Prepare() {
236  params_ = sockets_tcp_server::Close::Params::Create(*args_);
237  EXTENSION_FUNCTION_VALIDATE(params_.get());
238  return true;
239}
240
241void SocketsTcpServerCloseFunction::Work() {
242  ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
243  if (!socket) {
244    error_ = kSocketNotFoundError;
245    return;
246  }
247
248  RemoveSocket(params_->socket_id);
249  results_ = sockets_tcp_server::Close::Results::Create();
250}
251
252SocketsTcpServerGetInfoFunction::SocketsTcpServerGetInfoFunction() {}
253
254SocketsTcpServerGetInfoFunction::~SocketsTcpServerGetInfoFunction() {}
255
256bool SocketsTcpServerGetInfoFunction::Prepare() {
257  params_ = sockets_tcp_server::GetInfo::Params::Create(*args_);
258  EXTENSION_FUNCTION_VALIDATE(params_.get());
259  return true;
260}
261
262void SocketsTcpServerGetInfoFunction::Work() {
263  ResumableTCPServerSocket* socket = GetTcpSocket(params_->socket_id);
264  if (!socket) {
265    error_ = kSocketNotFoundError;
266    return;
267  }
268
269  linked_ptr<sockets_tcp_server::SocketInfo> socket_info =
270      CreateSocketInfo(params_->socket_id, socket);
271  results_ = sockets_tcp_server::GetInfo::Results::Create(*socket_info);
272}
273
274SocketsTcpServerGetSocketsFunction::SocketsTcpServerGetSocketsFunction() {}
275
276SocketsTcpServerGetSocketsFunction::~SocketsTcpServerGetSocketsFunction() {}
277
278bool SocketsTcpServerGetSocketsFunction::Prepare() { return true; }
279
280void SocketsTcpServerGetSocketsFunction::Work() {
281  std::vector<linked_ptr<sockets_tcp_server::SocketInfo> > socket_infos;
282  base::hash_set<int>* resource_ids = GetSocketIds();
283  if (resource_ids != NULL) {
284    for (base::hash_set<int>::iterator it = resource_ids->begin();
285         it != resource_ids->end();
286         ++it) {
287      int socket_id = *it;
288      ResumableTCPServerSocket* socket = GetTcpSocket(socket_id);
289      if (socket) {
290        socket_infos.push_back(CreateSocketInfo(socket_id, socket));
291      }
292    }
293  }
294  results_ = sockets_tcp_server::GetSockets::Results::Create(socket_infos);
295}
296
297}  // namespace core_api
298}  // namespace extensions
299