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_udp/sockets_udp_api.h"
6
7#include "content/public/common/socket_permission_request.h"
8#include "extensions/browser/api/socket/udp_socket.h"
9#include "extensions/browser/api/sockets_udp/udp_socket_event_dispatcher.h"
10#include "extensions/common/api/sockets/sockets_manifest_data.h"
11#include "net/base/net_errors.h"
12
13namespace extensions {
14namespace core_api {
15
16using content::SocketPermissionRequest;
17
18const char kSocketNotFoundError[] = "Socket not found";
19const char kPermissionError[] = "App does not have permission";
20const char kWildcardAddress[] = "*";
21const int kWildcardPort = 0;
22
23UDPSocketAsyncApiFunction::~UDPSocketAsyncApiFunction() {}
24
25scoped_ptr<SocketResourceManagerInterface>
26UDPSocketAsyncApiFunction::CreateSocketResourceManager() {
27  return scoped_ptr<SocketResourceManagerInterface>(
28             new SocketResourceManager<ResumableUDPSocket>()).Pass();
29}
30
31ResumableUDPSocket* UDPSocketAsyncApiFunction::GetUdpSocket(int socket_id) {
32  return static_cast<ResumableUDPSocket*>(GetSocket(socket_id));
33}
34
35UDPSocketExtensionWithDnsLookupFunction::
36    ~UDPSocketExtensionWithDnsLookupFunction() {}
37
38scoped_ptr<SocketResourceManagerInterface>
39UDPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() {
40  return scoped_ptr<SocketResourceManagerInterface>(
41             new SocketResourceManager<ResumableUDPSocket>()).Pass();
42}
43
44ResumableUDPSocket* UDPSocketExtensionWithDnsLookupFunction::GetUdpSocket(
45    int socket_id) {
46  return static_cast<ResumableUDPSocket*>(GetSocket(socket_id));
47}
48
49linked_ptr<sockets_udp::SocketInfo> CreateSocketInfo(
50    int socket_id,
51    ResumableUDPSocket* socket) {
52  linked_ptr<sockets_udp::SocketInfo> socket_info(
53      new sockets_udp::SocketInfo());
54  // This represents what we know about the socket, and does not call through
55  // to the system.
56  socket_info->socket_id = socket_id;
57  if (!socket->name().empty()) {
58    socket_info->name.reset(new std::string(socket->name()));
59  }
60  socket_info->persistent = socket->persistent();
61  if (socket->buffer_size() > 0) {
62    socket_info->buffer_size.reset(new int(socket->buffer_size()));
63  }
64  socket_info->paused = socket->paused();
65
66  // Grab the local address as known by the OS.
67  net::IPEndPoint localAddress;
68  if (socket->GetLocalAddress(&localAddress)) {
69    socket_info->local_address.reset(
70        new std::string(localAddress.ToStringWithoutPort()));
71    socket_info->local_port.reset(new int(localAddress.port()));
72  }
73
74  return socket_info;
75}
76
77void SetSocketProperties(ResumableUDPSocket* socket,
78                         sockets_udp::SocketProperties* properties) {
79  if (properties->name.get()) {
80    socket->set_name(*properties->name.get());
81  }
82  if (properties->persistent.get()) {
83    socket->set_persistent(*properties->persistent.get());
84  }
85  if (properties->buffer_size.get()) {
86    socket->set_buffer_size(*properties->buffer_size.get());
87  }
88}
89
90SocketsUdpCreateFunction::SocketsUdpCreateFunction() {}
91
92SocketsUdpCreateFunction::~SocketsUdpCreateFunction() {}
93
94bool SocketsUdpCreateFunction::Prepare() {
95  params_ = sockets_udp::Create::Params::Create(*args_);
96  EXTENSION_FUNCTION_VALIDATE(params_.get());
97  return true;
98}
99
100void SocketsUdpCreateFunction::Work() {
101  ResumableUDPSocket* socket = new ResumableUDPSocket(extension_->id());
102
103  sockets_udp::SocketProperties* properties = params_.get()->properties.get();
104  if (properties) {
105    SetSocketProperties(socket, properties);
106  }
107
108  sockets_udp::CreateInfo create_info;
109  create_info.socket_id = AddSocket(socket);
110  results_ = sockets_udp::Create::Results::Create(create_info);
111}
112
113SocketsUdpUpdateFunction::SocketsUdpUpdateFunction() {}
114
115SocketsUdpUpdateFunction::~SocketsUdpUpdateFunction() {}
116
117bool SocketsUdpUpdateFunction::Prepare() {
118  params_ = sockets_udp::Update::Params::Create(*args_);
119  EXTENSION_FUNCTION_VALIDATE(params_.get());
120  return true;
121}
122
123void SocketsUdpUpdateFunction::Work() {
124  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
125  if (!socket) {
126    error_ = kSocketNotFoundError;
127    return;
128  }
129
130  SetSocketProperties(socket, &params_.get()->properties);
131  results_ = sockets_udp::Update::Results::Create();
132}
133
134SocketsUdpSetPausedFunction::SocketsUdpSetPausedFunction()
135    : socket_event_dispatcher_(NULL) {}
136
137SocketsUdpSetPausedFunction::~SocketsUdpSetPausedFunction() {}
138
139bool SocketsUdpSetPausedFunction::Prepare() {
140  params_ = core_api::sockets_udp::SetPaused::Params::Create(*args_);
141  EXTENSION_FUNCTION_VALIDATE(params_.get());
142
143  socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(browser_context());
144  DCHECK(socket_event_dispatcher_)
145      << "There is no socket event dispatcher. "
146         "If this assertion is failing during a test, then it is likely that "
147         "TestExtensionSystem is failing to provide an instance of "
148         "UDPSocketEventDispatcher.";
149  return socket_event_dispatcher_ != NULL;
150}
151
152void SocketsUdpSetPausedFunction::Work() {
153  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
154  if (!socket) {
155    error_ = kSocketNotFoundError;
156    return;
157  }
158
159  if (socket->paused() != params_->paused) {
160    socket->set_paused(params_->paused);
161    if (socket->IsBound() && !params_->paused) {
162      socket_event_dispatcher_->OnSocketResume(extension_->id(),
163                                               params_->socket_id);
164    }
165  }
166
167  results_ = sockets_udp::SetPaused::Results::Create();
168}
169
170SocketsUdpBindFunction::SocketsUdpBindFunction()
171    : socket_event_dispatcher_(NULL) {}
172
173SocketsUdpBindFunction::~SocketsUdpBindFunction() {}
174
175bool SocketsUdpBindFunction::Prepare() {
176  params_ = sockets_udp::Bind::Params::Create(*args_);
177  EXTENSION_FUNCTION_VALIDATE(params_.get());
178
179  socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(browser_context());
180  DCHECK(socket_event_dispatcher_)
181      << "There is no socket event dispatcher. "
182         "If this assertion is failing during a test, then it is likely that "
183         "TestExtensionSystem is failing to provide an instance of "
184         "UDPSocketEventDispatcher.";
185  return socket_event_dispatcher_ != NULL;
186}
187
188void SocketsUdpBindFunction::Work() {
189  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
190  if (!socket) {
191    error_ = kSocketNotFoundError;
192    return;
193  }
194
195  content::SocketPermissionRequest param(
196      SocketPermissionRequest::UDP_BIND, params_->address, params_->port);
197  if (!SocketsManifestData::CheckRequest(extension(), param)) {
198    error_ = kPermissionError;
199    return;
200  }
201
202  int net_result = socket->Bind(params_->address, params_->port);
203  if (net_result == net::OK) {
204    socket_event_dispatcher_->OnSocketBind(extension_->id(),
205                                           params_->socket_id);
206  }
207
208  if (net_result != net::OK)
209    error_ = net::ErrorToString(net_result);
210  results_ = sockets_udp::Bind::Results::Create(net_result);
211}
212
213SocketsUdpSendFunction::SocketsUdpSendFunction() : io_buffer_size_(0) {}
214
215SocketsUdpSendFunction::~SocketsUdpSendFunction() {}
216
217bool SocketsUdpSendFunction::Prepare() {
218  params_ = sockets_udp::Send::Params::Create(*args_);
219  EXTENSION_FUNCTION_VALIDATE(params_.get());
220  io_buffer_size_ = params_->data.size();
221  io_buffer_ = new net::WrappedIOBuffer(params_->data.data());
222
223  return true;
224}
225
226void SocketsUdpSendFunction::AsyncWorkStart() {
227  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
228  if (!socket) {
229    error_ = kSocketNotFoundError;
230    AsyncWorkCompleted();
231    return;
232  }
233
234  content::SocketPermissionRequest param(
235      SocketPermissionRequest::UDP_SEND_TO, params_->address, params_->port);
236  if (!SocketsManifestData::CheckRequest(extension(), param)) {
237    error_ = kPermissionError;
238    AsyncWorkCompleted();
239    return;
240  }
241
242  StartDnsLookup(params_->address);
243}
244
245void SocketsUdpSendFunction::AfterDnsLookup(int lookup_result) {
246  if (lookup_result == net::OK) {
247    StartSendTo();
248  } else {
249    SetSendResult(lookup_result, -1);
250  }
251}
252
253void SocketsUdpSendFunction::StartSendTo() {
254  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
255  if (!socket) {
256    error_ = kSocketNotFoundError;
257    AsyncWorkCompleted();
258    return;
259  }
260
261  socket->SendTo(io_buffer_,
262                 io_buffer_size_,
263                 resolved_address_,
264                 params_->port,
265                 base::Bind(&SocketsUdpSendFunction::OnCompleted, this));
266}
267
268void SocketsUdpSendFunction::OnCompleted(int net_result) {
269  if (net_result >= net::OK) {
270    SetSendResult(net::OK, net_result);
271  } else {
272    SetSendResult(net_result, -1);
273  }
274}
275
276void SocketsUdpSendFunction::SetSendResult(int net_result, int bytes_sent) {
277  CHECK(net_result <= net::OK) << "Network status code must be < 0";
278
279  sockets_udp::SendInfo send_info;
280  send_info.result_code = net_result;
281  if (net_result == net::OK) {
282    send_info.bytes_sent.reset(new int(bytes_sent));
283  }
284
285  if (net_result != net::OK)
286    error_ = net::ErrorToString(net_result);
287  results_ = sockets_udp::Send::Results::Create(send_info);
288  AsyncWorkCompleted();
289}
290
291SocketsUdpCloseFunction::SocketsUdpCloseFunction() {}
292
293SocketsUdpCloseFunction::~SocketsUdpCloseFunction() {}
294
295bool SocketsUdpCloseFunction::Prepare() {
296  params_ = sockets_udp::Close::Params::Create(*args_);
297  EXTENSION_FUNCTION_VALIDATE(params_.get());
298  return true;
299}
300
301void SocketsUdpCloseFunction::Work() {
302  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
303  if (!socket) {
304    error_ = kSocketNotFoundError;
305    return;
306  }
307
308  socket->Disconnect();
309  RemoveSocket(params_->socket_id);
310  results_ = sockets_udp::Close::Results::Create();
311}
312
313SocketsUdpGetInfoFunction::SocketsUdpGetInfoFunction() {}
314
315SocketsUdpGetInfoFunction::~SocketsUdpGetInfoFunction() {}
316
317bool SocketsUdpGetInfoFunction::Prepare() {
318  params_ = sockets_udp::GetInfo::Params::Create(*args_);
319  EXTENSION_FUNCTION_VALIDATE(params_.get());
320  return true;
321}
322
323void SocketsUdpGetInfoFunction::Work() {
324  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
325  if (!socket) {
326    error_ = kSocketNotFoundError;
327    return;
328  }
329
330  linked_ptr<sockets_udp::SocketInfo> socket_info =
331      CreateSocketInfo(params_->socket_id, socket);
332  results_ = sockets_udp::GetInfo::Results::Create(*socket_info);
333}
334
335SocketsUdpGetSocketsFunction::SocketsUdpGetSocketsFunction() {}
336
337SocketsUdpGetSocketsFunction::~SocketsUdpGetSocketsFunction() {}
338
339bool SocketsUdpGetSocketsFunction::Prepare() { return true; }
340
341void SocketsUdpGetSocketsFunction::Work() {
342  std::vector<linked_ptr<sockets_udp::SocketInfo> > socket_infos;
343  base::hash_set<int>* resource_ids = GetSocketIds();
344  if (resource_ids != NULL) {
345    for (base::hash_set<int>::iterator it = resource_ids->begin();
346         it != resource_ids->end();
347         ++it) {
348      int socket_id = *it;
349      ResumableUDPSocket* socket = GetUdpSocket(socket_id);
350      if (socket) {
351        socket_infos.push_back(CreateSocketInfo(socket_id, socket));
352      }
353    }
354  }
355  results_ = sockets_udp::GetSockets::Results::Create(socket_infos);
356}
357
358SocketsUdpJoinGroupFunction::SocketsUdpJoinGroupFunction() {}
359
360SocketsUdpJoinGroupFunction::~SocketsUdpJoinGroupFunction() {}
361
362bool SocketsUdpJoinGroupFunction::Prepare() {
363  params_ = sockets_udp::JoinGroup::Params::Create(*args_);
364  EXTENSION_FUNCTION_VALIDATE(params_.get());
365  return true;
366}
367
368void SocketsUdpJoinGroupFunction::Work() {
369  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
370  if (!socket) {
371    error_ = kSocketNotFoundError;
372    return;
373  }
374
375  content::SocketPermissionRequest param(
376      SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
377      kWildcardAddress,
378      kWildcardPort);
379  if (!SocketsManifestData::CheckRequest(extension(), param)) {
380    error_ = kPermissionError;
381    return;
382  }
383
384  int net_result = socket->JoinGroup(params_->address);
385  if (net_result != net::OK)
386    error_ = net::ErrorToString(net_result);
387  results_ = sockets_udp::JoinGroup::Results::Create(net_result);
388}
389
390SocketsUdpLeaveGroupFunction::SocketsUdpLeaveGroupFunction() {}
391
392SocketsUdpLeaveGroupFunction::~SocketsUdpLeaveGroupFunction() {}
393
394bool SocketsUdpLeaveGroupFunction::Prepare() {
395  params_ = core_api::sockets_udp::LeaveGroup::Params::Create(*args_);
396  EXTENSION_FUNCTION_VALIDATE(params_.get());
397  return true;
398}
399
400void SocketsUdpLeaveGroupFunction::Work() {
401  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
402  if (!socket) {
403    error_ = kSocketNotFoundError;
404    return;
405  }
406
407  content::SocketPermissionRequest param(
408      SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
409      kWildcardAddress,
410      kWildcardPort);
411  if (!SocketsManifestData::CheckRequest(extension(), param)) {
412    error_ = kPermissionError;
413    return;
414  }
415
416  int net_result = socket->LeaveGroup(params_->address);
417  if (net_result != net::OK)
418    error_ = net::ErrorToString(net_result);
419  results_ = sockets_udp::LeaveGroup::Results::Create(net_result);
420}
421
422SocketsUdpSetMulticastTimeToLiveFunction::
423    SocketsUdpSetMulticastTimeToLiveFunction() {}
424
425SocketsUdpSetMulticastTimeToLiveFunction::
426    ~SocketsUdpSetMulticastTimeToLiveFunction() {}
427
428bool SocketsUdpSetMulticastTimeToLiveFunction::Prepare() {
429  params_ =
430      core_api::sockets_udp::SetMulticastTimeToLive::Params::Create(*args_);
431  EXTENSION_FUNCTION_VALIDATE(params_.get());
432  return true;
433}
434
435void SocketsUdpSetMulticastTimeToLiveFunction::Work() {
436  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
437  if (!socket) {
438    error_ = kSocketNotFoundError;
439    return;
440  }
441
442  int net_result = socket->SetMulticastTimeToLive(params_->ttl);
443  if (net_result != net::OK)
444    error_ = net::ErrorToString(net_result);
445  results_ = sockets_udp::SetMulticastTimeToLive::Results::Create(net_result);
446}
447
448SocketsUdpSetMulticastLoopbackModeFunction::
449    SocketsUdpSetMulticastLoopbackModeFunction() {}
450
451SocketsUdpSetMulticastLoopbackModeFunction::
452    ~SocketsUdpSetMulticastLoopbackModeFunction() {}
453
454bool SocketsUdpSetMulticastLoopbackModeFunction::Prepare() {
455  params_ =
456      core_api::sockets_udp::SetMulticastLoopbackMode::Params::Create(*args_);
457  EXTENSION_FUNCTION_VALIDATE(params_.get());
458  return true;
459}
460
461void SocketsUdpSetMulticastLoopbackModeFunction::Work() {
462  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
463  if (!socket) {
464    error_ = kSocketNotFoundError;
465    return;
466  }
467
468  int net_result = socket->SetMulticastLoopbackMode(params_->enabled);
469  if (net_result != net::OK)
470    error_ = net::ErrorToString(net_result);
471  results_ = sockets_udp::SetMulticastLoopbackMode::Results::Create(net_result);
472}
473
474SocketsUdpGetJoinedGroupsFunction::SocketsUdpGetJoinedGroupsFunction() {}
475
476SocketsUdpGetJoinedGroupsFunction::~SocketsUdpGetJoinedGroupsFunction() {}
477
478bool SocketsUdpGetJoinedGroupsFunction::Prepare() {
479  params_ = core_api::sockets_udp::GetJoinedGroups::Params::Create(*args_);
480  EXTENSION_FUNCTION_VALIDATE(params_.get());
481  return true;
482}
483
484void SocketsUdpGetJoinedGroupsFunction::Work() {
485  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
486  if (!socket) {
487    error_ = kSocketNotFoundError;
488    return;
489  }
490
491  content::SocketPermissionRequest param(
492      SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
493      kWildcardAddress,
494      kWildcardPort);
495  if (!SocketsManifestData::CheckRequest(extension(), param)) {
496    error_ = kPermissionError;
497    return;
498  }
499
500  const std::vector<std::string>& groups = socket->GetJoinedGroups();
501  results_ = sockets_udp::GetJoinedGroups::Results::Create(groups);
502}
503
504}  // namespace core_api
505}  // namespace extensions
506