Home | History | Annotate | Download | only in socket
      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 
     20 namespace nacl_io {
     21 
     22 SocketNode::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 
     34 SocketNode::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 
     47 void 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.
     61 Error 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.
     72 Error 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 
     79 Error 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 
     86 NetAddressInterface* SocketNode::NetInterface() {
     87   if (filesystem_->ppapi() == NULL)
     88     return NULL;
     89 
     90   return filesystem_->ppapi()->GetNetAddressInterface();
     91 }
     92 
     93 TCPSocketInterface* SocketNode::TCPInterface() {
     94   if (filesystem_->ppapi() == NULL)
     95     return NULL;
     96 
     97   return filesystem_->ppapi()->GetTCPSocketInterface();
     98 }
     99 
    100 UDPSocketInterface* SocketNode::UDPInterface() {
    101   if (filesystem_->ppapi() == NULL)
    102     return NULL;
    103 
    104   return filesystem_->ppapi()->GetUDPSocketInterface();
    105 }
    106 
    107 PP_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 
    146 socklen_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 
    182 bool 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 
    201 Error SocketNode::Accept(const HandleAttr& attr,
    202                          PP_Resource* new_sock,
    203                          struct sockaddr* addr,
    204                          socklen_t* len) {
    205   return ENOSYS;
    206 }
    207 
    208 Error 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 
    220 Error SocketNode::Listen(int backlog) {
    221   return EOPNOTSUPP;
    222 }
    223 
    224 Error 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 
    269 Error 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 
    318 Error SocketNode::Bind(const struct sockaddr* addr, socklen_t len) {
    319   return EINVAL;
    320 }
    321 
    322 Error 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 
    330 Error 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 
    349 Error 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 
    382 Error 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 
    390 Error 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 
    409 Error 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 
    443 void 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 
    449 Error SocketNode::Shutdown(int how) {
    450   return EOPNOTSUPP;
    451 }
    452 
    453 Error 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 
    466 Error 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