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 "nacl_io/socket/socket_node.h"
6
7#include "nacl_io/ossocket.h"
8#ifdef PROVIDES_SOCKET_API
9
10#include <errno.h>
11#include <string.h>
12
13#include "nacl_io/filesystem.h"
14#include "nacl_io/kernel_handle.h"
15#include "nacl_io/pepper_interface.h"
16
17#include "ppapi/c/pp_resource.h"
18#include "ppapi/c/ppb_net_address.h"
19
20namespace nacl_io {
21
22SocketNode::SocketNode(Filesystem* filesystem)
23    : StreamNode(filesystem),
24      socket_resource_(0),
25      local_addr_(0),
26      remote_addr_(0),
27      socket_flags_(0),
28      last_errno_(0),
29      keep_alive_(false) {
30  memset(&linger_, 0, sizeof(linger_));
31  SetType(S_IFSOCK);
32}
33
34SocketNode::SocketNode(Filesystem* filesystem, PP_Resource socket)
35    : StreamNode(filesystem),
36      socket_resource_(socket),
37      local_addr_(0),
38      remote_addr_(0),
39      socket_flags_(0),
40      last_errno_(0),
41      keep_alive_(false) {
42  memset(&linger_, 0, sizeof(linger_));
43  SetType(S_IFSOCK);
44  filesystem_->ppapi()->AddRefResource(socket_resource_);
45}
46
47void SocketNode::Destroy() {
48  if (socket_resource_)
49    filesystem_->ppapi()->ReleaseResource(socket_resource_);
50  if (local_addr_)
51    filesystem_->ppapi()->ReleaseResource(local_addr_);
52  if (remote_addr_)
53    filesystem_->ppapi()->ReleaseResource(remote_addr_);
54
55  socket_resource_ = 0;
56  local_addr_ = 0;
57  remote_addr_ = 0;
58}
59
60// Assume that |addr| and |out_addr| are non-NULL.
61Error SocketNode::MMap(void* addr,
62                       size_t length,
63                       int prot,
64                       int flags,
65                       size_t offset,
66                       void** out_addr) {
67  return EACCES;
68}
69
70// Normal read/write operations on a Socket are equivalent to
71// send/recv with a flag value of 0.
72Error SocketNode::Read(const HandleAttr& attr,
73                       void* buf,
74                       size_t count,
75                       int* out_bytes) {
76  return Recv(attr, buf, count, 0, out_bytes);
77}
78
79Error SocketNode::Write(const HandleAttr& attr,
80                        const void* buf,
81                        size_t count,
82                        int* out_bytes) {
83  return Send(attr, buf, count, 0, out_bytes);
84}
85
86NetAddressInterface* SocketNode::NetInterface() {
87  if (filesystem_->ppapi() == NULL)
88    return NULL;
89
90  return filesystem_->ppapi()->GetNetAddressInterface();
91}
92
93TCPSocketInterface* SocketNode::TCPInterface() {
94  if (filesystem_->ppapi() == NULL)
95    return NULL;
96
97  return filesystem_->ppapi()->GetTCPSocketInterface();
98}
99
100UDPSocketInterface* SocketNode::UDPInterface() {
101  if (filesystem_->ppapi() == NULL)
102    return NULL;
103
104  return filesystem_->ppapi()->GetUDPSocketInterface();
105}
106
107PP_Resource SocketNode::SockAddrToResource(const struct sockaddr* addr,
108                                           socklen_t len) {
109  if (NULL == addr)
110    return 0;
111
112  if (AF_INET == addr->sa_family) {
113    PP_NetAddress_IPv4 addr4;
114    const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(addr);
115
116    if (len != sizeof(sockaddr_in))
117      return 0;
118
119    memset(&addr4, 0, sizeof(addr4));
120
121    addr4.port = sin->sin_port;
122    memcpy(addr4.addr, &sin->sin_addr, sizeof(addr4.addr));
123    return filesystem_->ppapi()
124        ->GetNetAddressInterface()
125        ->CreateFromIPv4Address(filesystem_->ppapi()->GetInstance(), &addr4);
126  }
127
128  if (AF_INET6 == addr->sa_family) {
129    PP_NetAddress_IPv6 addr6;
130    const sockaddr_in6* sin = reinterpret_cast<const sockaddr_in6*>(addr);
131
132    if (len != sizeof(sockaddr_in6))
133      return 0;
134
135    memset(&addr6, 0, sizeof(addr6));
136
137    addr6.port = sin->sin6_port;
138    memcpy(addr6.addr, &sin->sin6_addr, sizeof(addr6.addr));
139    return filesystem_->ppapi()
140        ->GetNetAddressInterface()
141        ->CreateFromIPv6Address(filesystem_->ppapi()->GetInstance(), &addr6);
142  }
143  return 0;
144}
145
146socklen_t SocketNode::ResourceToSockAddr(PP_Resource addr,
147                                         socklen_t len,
148                                         struct sockaddr* out_addr) {
149  if (0 == addr)
150    return 0;
151
152  PP_NetAddress_IPv4 ipv4;
153  PP_NetAddress_IPv6 ipv6;
154
155  if (PP_TRUE == NetInterface()->DescribeAsIPv4Address(addr, &ipv4)) {
156    sockaddr_in addr4;
157    addr4.sin_family = AF_INET;
158    addr4.sin_port = ipv4.port;
159    memcpy(&addr4.sin_addr, ipv4.addr, sizeof(ipv4.addr));
160    memcpy(out_addr, &addr4,
161           std::min(len, static_cast<socklen_t>(sizeof(addr4))));
162
163    // Returns required size not copied size like getpeername/getsockname.
164    return sizeof(addr4);
165  }
166
167  if (PP_TRUE == NetInterface()->DescribeAsIPv6Address(addr, &ipv6)) {
168    sockaddr_in6 addr6;
169    addr6.sin6_family = AF_INET6;
170    addr6.sin6_port = ipv6.port;
171    memcpy(&addr6.sin6_addr, ipv6.addr, sizeof(ipv6.addr));
172    memcpy(out_addr, &addr6,
173           std::min(len, static_cast<socklen_t>(sizeof(addr6))));
174
175    // Returns required size not copied size like getpeername/getsockname.
176    return sizeof(addr6);
177  }
178
179  return 0;
180}
181
182bool SocketNode::IsEquivalentAddress(PP_Resource addr1, PP_Resource addr2) {
183  if (addr1 == addr2)
184    return true;
185
186  char data1[sizeof(sockaddr_in6)];
187  char data2[sizeof(sockaddr_in6)];
188
189  sockaddr* saddr1 = reinterpret_cast<sockaddr*>(data1);
190  sockaddr* saddr2 = reinterpret_cast<sockaddr*>(data2);
191
192  socklen_t len1 = ResourceToSockAddr(addr1, sizeof(data1), saddr1);
193  socklen_t len2 = ResourceToSockAddr(addr2, sizeof(data2), saddr2);
194
195  if (len1 != len2)
196    return false;
197
198  return memcmp(saddr1, saddr2, len1) == 0;
199}
200
201Error SocketNode::Accept(const HandleAttr& attr,
202                         PP_Resource* new_sock,
203                         struct sockaddr* addr,
204                         socklen_t* len) {
205  return ENOSYS;
206}
207
208Error SocketNode::Connect(const HandleAttr& attr,
209                          const struct sockaddr* addr,
210                          socklen_t len) {
211  if (len < 1)
212    return EINVAL;
213
214  if (NULL == addr)
215    return EFAULT;
216
217  return EOPNOTSUPP;
218}
219
220Error SocketNode::Listen(int backlog) {
221  return EOPNOTSUPP;
222}
223
224Error SocketNode::GetSockOpt(int lvl,
225                             int optname,
226                             void* optval,
227                             socklen_t* len) {
228  if (lvl != SOL_SOCKET)
229    return ENOPROTOOPT;
230
231  AUTO_LOCK(node_lock_);
232
233  int value = 0;
234  socklen_t value_len = 0;
235  void* value_ptr = NULL;
236
237  switch (optname) {
238    case SO_REUSEADDR:
239      // SO_REUSEADDR is effectively always on since we can't
240      // disable it with PPAPI sockets.
241      value = 1;
242      value_ptr = &value;
243      value_len = sizeof(value);
244      break;
245    case SO_LINGER:
246      value_ptr = &linger_;
247      value_len = sizeof(linger_);
248      break;
249    case SO_KEEPALIVE:
250      value = keep_alive_;
251      value_ptr = &value;
252      value_len = sizeof(value);
253      break;
254    case SO_ERROR:
255      value_ptr = &last_errno_;
256      value_len = sizeof(last_errno_);
257      last_errno_ = 0;
258      break;
259    default:
260      return ENOPROTOOPT;
261  }
262
263  int copy_bytes = std::min(value_len, *len);
264  memcpy(optval, value_ptr, copy_bytes);
265  *len = value_len;
266  return 0;
267}
268
269Error SocketNode::SetSockOpt(int lvl,
270                             int optname,
271                             const void* optval,
272                             socklen_t len) {
273  size_t buflen = static_cast<size_t>(len);
274
275  if (lvl != SOL_SOCKET)
276    return ENOPROTOOPT;
277
278  AUTO_LOCK(node_lock_);
279
280  switch (optname) {
281    case SO_REUSEADDR: {
282      // SO_REUSEADDR is effectivly always on since we can't
283      // disable it with PPAPI sockets. Just return success
284      // here regardless.
285      if (buflen < sizeof(int))
286        return EINVAL;
287      return 0;
288    }
289    case SO_LINGER: {
290      // Not supported by the PPAPI interface but we preserve
291      // the settings and pretend to support it.
292      if (buflen < sizeof(struct linger))
293        return EINVAL;
294      struct linger new_linger = *static_cast<const linger*>(optval);
295      // Don't allow setting linger to be enabled until we
296      // implement the required synchronous shutdown()/close().
297      // TODO(sbc): remove this after http://crbug.com/312401
298      // gets fixed.
299      if (new_linger.l_onoff != 0)
300        return EINVAL;
301      linger_ = new_linger;
302      return 0;
303    }
304    case SO_KEEPALIVE: {
305      // Not supported by the PPAPI interface but we preserve
306      // the flag and pretend to support it.
307      if (buflen < sizeof(int))
308        return EINVAL;
309      int value = *static_cast<const int*>(optval);
310      keep_alive_ = value != 0;
311      return 0;
312    }
313  }
314
315  return ENOPROTOOPT;
316}
317
318Error SocketNode::Bind(const struct sockaddr* addr, socklen_t len) {
319  return EINVAL;
320}
321
322Error SocketNode::Recv(const HandleAttr& attr,
323                       void* buf,
324                       size_t len,
325                       int flags,
326                       int* out_len) {
327  return RecvFrom(attr, buf, len, flags, NULL, 0, out_len);
328}
329
330Error SocketNode::RecvFrom(const HandleAttr& attr,
331                           void* buf,
332                           size_t len,
333                           int flags,
334                           struct sockaddr* src_addr,
335                           socklen_t* addrlen,
336                           int* out_len) {
337  PP_Resource addr = 0;
338  Error err = RecvHelper(attr, buf, len, flags, &addr, out_len);
339  if (0 == err && 0 != addr) {
340    if (src_addr)
341      *addrlen = ResourceToSockAddr(addr, *addrlen, src_addr);
342
343    filesystem_->ppapi()->ReleaseResource(addr);
344  }
345
346  return err;
347}
348
349Error SocketNode::RecvHelper(const HandleAttr& attr,
350                             void* buf,
351                             size_t len,
352                             int flags,
353                             PP_Resource* addr,
354                             int* out_len) {
355  if (0 == socket_resource_)
356    return EBADF;
357
358  int ms = read_timeout_;
359  if ((flags & MSG_DONTWAIT) || !attr.IsBlocking())
360    ms = 0;
361
362  // TODO(noelallen) BUG=295177
363  // For UDP we should support filtering packets when using connect
364  EventListenerLock wait(GetEventEmitter());
365  Error err = wait.WaitOnEvent(POLLIN, ms);
366
367  // Timeout is treated as a would block for sockets.
368  if (ETIMEDOUT == err)
369    return EWOULDBLOCK;
370
371  if (err)
372    return err;
373
374  err = Recv_Locked(buf, len, addr, out_len);
375
376  // We must have read from then inputbuffer, so Q up some receive work.
377  if ((err == 0) && *out_len)
378    QueueInput();
379  return err;
380}
381
382Error SocketNode::Send(const HandleAttr& attr,
383                       const void* buf,
384                       size_t len,
385                       int flags,
386                       int* out_len) {
387  return SendHelper(attr, buf, len, flags, remote_addr_, out_len);
388}
389
390Error SocketNode::SendTo(const HandleAttr& attr,
391                         const void* buf,
392                         size_t len,
393                         int flags,
394                         const struct sockaddr* dest_addr,
395                         socklen_t addrlen,
396                         int* out_len) {
397  if ((NULL == dest_addr) && (0 == remote_addr_))
398    return EDESTADDRREQ;
399
400  PP_Resource addr = SockAddrToResource(dest_addr, addrlen);
401  if (0 == addr)
402    return EINVAL;
403
404  Error err = SendHelper(attr, buf, len, flags, addr, out_len);
405  filesystem_->ppapi()->ReleaseResource(addr);
406  return err;
407}
408
409Error SocketNode::SendHelper(const HandleAttr& attr,
410                             const void* buf,
411                             size_t len,
412                             int flags,
413                             PP_Resource addr,
414                             int* out_len) {
415  if (0 == socket_resource_)
416    return EBADF;
417
418  if (0 == addr)
419    return ENOTCONN;
420
421  int ms = write_timeout_;
422  if ((flags & MSG_DONTWAIT) || !attr.IsBlocking())
423    ms = 0;
424
425  EventListenerLock wait(GetEventEmitter());
426  Error err = wait.WaitOnEvent(POLLOUT, ms);
427
428  // Timeout is treated as a would block for sockets.
429  if (ETIMEDOUT == err)
430    return EWOULDBLOCK;
431
432  if (err)
433    return err;
434
435  err = Send_Locked(buf, len, addr, out_len);
436
437  // We must have added to the output buffer, so Q up some transmit work.
438  if ((err == 0) && *out_len)
439    QueueOutput();
440  return err;
441}
442
443void SocketNode::SetError_Locked(int pp_error_num) {
444  SetStreamFlags(SSF_ERROR | SSF_CLOSED);
445  ClearStreamFlags(SSF_CAN_SEND | SSF_CAN_RECV);
446  last_errno_ = PPErrorToErrno(pp_error_num);
447}
448
449Error SocketNode::Shutdown(int how) {
450  return EOPNOTSUPP;
451}
452
453Error SocketNode::GetPeerName(struct sockaddr* addr, socklen_t* len) {
454  if (NULL == addr || NULL == len)
455    return EFAULT;
456
457  AUTO_LOCK(node_lock_);
458  if (remote_addr_ != 0) {
459    *len = ResourceToSockAddr(remote_addr_, *len, addr);
460    return 0;
461  }
462
463  return ENOTCONN;
464}
465
466Error SocketNode::GetSockName(struct sockaddr* addr, socklen_t* len) {
467  if (NULL == addr || NULL == len)
468    return EFAULT;
469
470  AUTO_LOCK(node_lock_);
471  if (local_addr_ == 0) {
472    // getsockname succeeds even if the socket is not bound. In this case,
473    // just return address 0, port 0.
474    memset(addr, 0, *len);
475    return 0;
476  }
477
478  *len = ResourceToSockAddr(local_addr_, *len, addr);
479  return 0;
480}
481
482}  // namespace nacl_io
483
484#endif  // PROVIDES_SOCKET_API
485