1// Copyright 2013 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 "chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h"
6
7#include "chrome/browser/extensions/api/socket/udp_socket.h"
8#include "chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h"
9#include "chrome/common/extensions/api/sockets/sockets_manifest_data.h"
10#include "content/public/common/socket_permission_request.h"
11#include "net/base/net_errors.h"
12
13namespace extensions {
14namespace 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>
26    UDPSocketAsyncApiFunction::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>
39    UDPSocketExtensionWithDnsLookupFunction::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_ = api::sockets_udp::SetPaused::Params::Create(*args_);
141  EXTENSION_FUNCTION_VALIDATE(params_.get());
142
143  socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(GetProfile());
144  DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
145    "If this assertion is failing during a test, then it is likely that "
146    "TestExtensionSystem is failing to provide an instance of "
147    "UDPSocketEventDispatcher.";
148  return socket_event_dispatcher_ != NULL;
149}
150
151void SocketsUdpSetPausedFunction::Work() {
152  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
153  if (!socket) {
154    error_ = kSocketNotFoundError;
155    return;
156  }
157
158  if (socket->paused() != params_->paused) {
159    socket->set_paused(params_->paused);
160    if (socket->IsBound() && !params_->paused) {
161      socket_event_dispatcher_->OnSocketResume(extension_->id(),
162                                               params_->socket_id);
163    }
164  }
165
166  results_ = sockets_udp::SetPaused::Results::Create();
167}
168
169SocketsUdpBindFunction::SocketsUdpBindFunction()
170    : socket_event_dispatcher_(NULL) {
171}
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(GetProfile());
180  DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. "
181    "If this assertion is failing during a test, then it is likely that "
182    "TestExtensionSystem is failing to provide an instance of "
183    "UDPSocketEventDispatcher.";
184  return socket_event_dispatcher_ != NULL;
185}
186
187void SocketsUdpBindFunction::Work() {
188  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
189  if (!socket) {
190    error_ = kSocketNotFoundError;
191    return;
192  }
193
194  content::SocketPermissionRequest param(
195      SocketPermissionRequest::UDP_BIND,
196      params_->address,
197      params_->port);
198  if (!SocketsManifestData::CheckRequest(GetExtension(), param)) {
199    error_ = kPermissionError;
200    return;
201  }
202
203  int net_result = socket->Bind(params_->address, params_->port);
204  if (net_result == net::OK) {
205    socket_event_dispatcher_->OnSocketBind(extension_->id(),
206                                           params_->socket_id);
207  }
208
209  if (net_result != net::OK)
210    error_ = net::ErrorToString(net_result);
211  results_ = sockets_udp::Bind::Results::Create(net_result);
212}
213
214SocketsUdpSendFunction::SocketsUdpSendFunction()
215    : io_buffer_size_(0) {}
216
217SocketsUdpSendFunction::~SocketsUdpSendFunction() {}
218
219bool SocketsUdpSendFunction::Prepare() {
220  params_ = sockets_udp::Send::Params::Create(*args_);
221  EXTENSION_FUNCTION_VALIDATE(params_.get());
222  io_buffer_size_ = params_->data.size();
223  io_buffer_ = new net::WrappedIOBuffer(params_->data.data());
224
225  return true;
226}
227
228void SocketsUdpSendFunction::AsyncWorkStart() {
229  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
230  if (!socket) {
231    error_ = kSocketNotFoundError;
232    AsyncWorkCompleted();
233    return;
234  }
235
236  content::SocketPermissionRequest param(
237      SocketPermissionRequest::UDP_SEND_TO,
238      params_->address,
239      params_->port);
240  if (!SocketsManifestData::CheckRequest(GetExtension(), param)) {
241    error_ = kPermissionError;
242    AsyncWorkCompleted();
243    return;
244  }
245
246  StartDnsLookup(params_->address);
247}
248
249void SocketsUdpSendFunction::AfterDnsLookup(int lookup_result) {
250  if (lookup_result == net::OK) {
251    StartSendTo();
252  } else {
253    SetSendResult(lookup_result, -1);
254  }
255}
256
257void SocketsUdpSendFunction::StartSendTo() {
258  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
259  if (!socket) {
260    error_ = kSocketNotFoundError;
261    AsyncWorkCompleted();
262    return;
263  }
264
265  socket->SendTo(io_buffer_, io_buffer_size_, resolved_address_, params_->port,
266                  base::Bind(&SocketsUdpSendFunction::OnCompleted, this));
267}
268
269void SocketsUdpSendFunction::OnCompleted(int net_result) {
270  if (net_result >= net::OK) {
271    SetSendResult(net::OK, net_result);
272  } else {
273    SetSendResult(net_result, -1);
274  }
275}
276
277void SocketsUdpSendFunction::SetSendResult(int net_result, int bytes_sent) {
278  CHECK(net_result <= net::OK) << "Network status code must be < 0";
279
280  sockets_udp::SendInfo send_info;
281  send_info.result_code = net_result;
282  if (net_result == net::OK) {
283    send_info.bytes_sent.reset(new int(bytes_sent));
284  }
285
286  if (net_result != net::OK)
287    error_ = net::ErrorToString(net_result);
288  results_ = sockets_udp::Send::Results::Create(send_info);
289  AsyncWorkCompleted();
290}
291
292SocketsUdpCloseFunction::SocketsUdpCloseFunction() {}
293
294SocketsUdpCloseFunction::~SocketsUdpCloseFunction() {}
295
296bool SocketsUdpCloseFunction::Prepare() {
297  params_ = sockets_udp::Close::Params::Create(*args_);
298  EXTENSION_FUNCTION_VALIDATE(params_.get());
299  return true;
300}
301
302void SocketsUdpCloseFunction::Work() {
303  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
304  if (!socket) {
305    error_ = kSocketNotFoundError;
306    return;
307  }
308
309  socket->Disconnect();
310  RemoveSocket(params_->socket_id);
311  results_ = sockets_udp::Close::Results::Create();
312}
313
314SocketsUdpGetInfoFunction::SocketsUdpGetInfoFunction() {}
315
316SocketsUdpGetInfoFunction::~SocketsUdpGetInfoFunction() {}
317
318bool SocketsUdpGetInfoFunction::Prepare() {
319  params_ = sockets_udp::GetInfo::Params::Create(*args_);
320  EXTENSION_FUNCTION_VALIDATE(params_.get());
321  return true;
322}
323
324void SocketsUdpGetInfoFunction::Work() {
325  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
326  if (!socket) {
327    error_ = kSocketNotFoundError;
328    return;
329  }
330
331  linked_ptr<sockets_udp::SocketInfo> socket_info =
332      CreateSocketInfo(params_->socket_id, socket);
333  results_ = sockets_udp::GetInfo::Results::Create(*socket_info);
334}
335
336SocketsUdpGetSocketsFunction::SocketsUdpGetSocketsFunction() {}
337
338SocketsUdpGetSocketsFunction::~SocketsUdpGetSocketsFunction() {}
339
340bool SocketsUdpGetSocketsFunction::Prepare() {
341  return true;
342}
343
344void SocketsUdpGetSocketsFunction::Work() {
345  std::vector<linked_ptr<sockets_udp::SocketInfo> > socket_infos;
346  base::hash_set<int>* resource_ids = GetSocketIds();
347  if (resource_ids != NULL) {
348    for (base::hash_set<int>::iterator it = resource_ids->begin();
349             it != resource_ids->end(); ++it) {
350      int socket_id = *it;
351      ResumableUDPSocket* socket = GetUdpSocket(socket_id);
352      if (socket) {
353        socket_infos.push_back(CreateSocketInfo(socket_id, socket));
354      }
355    }
356  }
357  results_ = sockets_udp::GetSockets::Results::Create(socket_infos);
358}
359
360SocketsUdpJoinGroupFunction::SocketsUdpJoinGroupFunction() {}
361
362SocketsUdpJoinGroupFunction::~SocketsUdpJoinGroupFunction() {}
363
364bool SocketsUdpJoinGroupFunction::Prepare() {
365  params_ = sockets_udp::JoinGroup::Params::Create(*args_);
366  EXTENSION_FUNCTION_VALIDATE(params_.get());
367  return true;
368}
369
370void SocketsUdpJoinGroupFunction::Work() {
371  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
372  if (!socket) {
373    error_ = kSocketNotFoundError;
374    return;
375  }
376
377  content::SocketPermissionRequest param(
378      SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
379      kWildcardAddress,
380      kWildcardPort);
381  if (!SocketsManifestData::CheckRequest(GetExtension(), param)) {
382    error_ = kPermissionError;
383    return;
384  }
385
386  int net_result = socket->JoinGroup(params_->address);
387  if (net_result != net::OK)
388    error_ = net::ErrorToString(net_result);
389  results_ = sockets_udp::JoinGroup::Results::Create(net_result);
390}
391
392SocketsUdpLeaveGroupFunction::SocketsUdpLeaveGroupFunction() {}
393
394SocketsUdpLeaveGroupFunction::~SocketsUdpLeaveGroupFunction() {}
395
396bool SocketsUdpLeaveGroupFunction::Prepare() {
397  params_ = api::sockets_udp::LeaveGroup::Params::Create(*args_);
398  EXTENSION_FUNCTION_VALIDATE(params_.get());
399  return true;
400}
401
402void SocketsUdpLeaveGroupFunction::Work() {
403  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
404  if (!socket) {
405    error_ = kSocketNotFoundError;
406    return;
407  }
408
409  content::SocketPermissionRequest param(
410      SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
411      kWildcardAddress,
412      kWildcardPort);
413  if (!SocketsManifestData::CheckRequest(GetExtension(), param)) {
414    error_ = kPermissionError;
415    return;
416  }
417
418  int net_result = socket->LeaveGroup(params_->address);
419  if (net_result != net::OK)
420    error_ = net::ErrorToString(net_result);
421  results_ = sockets_udp::LeaveGroup::Results::Create(net_result);
422}
423
424SocketsUdpSetMulticastTimeToLiveFunction::
425    SocketsUdpSetMulticastTimeToLiveFunction() {}
426
427SocketsUdpSetMulticastTimeToLiveFunction::
428    ~SocketsUdpSetMulticastTimeToLiveFunction() {}
429
430bool SocketsUdpSetMulticastTimeToLiveFunction::Prepare() {
431  params_ = api::sockets_udp::SetMulticastTimeToLive::Params::Create(*args_);
432  EXTENSION_FUNCTION_VALIDATE(params_.get());
433  return true;
434}
435
436void SocketsUdpSetMulticastTimeToLiveFunction::Work() {
437  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
438  if (!socket) {
439    error_ = kSocketNotFoundError;
440    return;
441  }
442
443  int net_result = socket->SetMulticastTimeToLive(params_->ttl);
444  if (net_result != net::OK)
445    error_ = net::ErrorToString(net_result);
446  results_ = sockets_udp::SetMulticastTimeToLive::Results::Create(net_result);
447}
448
449SocketsUdpSetMulticastLoopbackModeFunction::
450    SocketsUdpSetMulticastLoopbackModeFunction() {}
451
452SocketsUdpSetMulticastLoopbackModeFunction::
453  ~SocketsUdpSetMulticastLoopbackModeFunction() {}
454
455bool SocketsUdpSetMulticastLoopbackModeFunction::Prepare() {
456  params_ = 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_ = 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(GetExtension(), 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 api
505}  // namespace extensions
506