• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SocketNode(Filesystem * filesystem)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 
SocketNode(Filesystem * filesystem,PP_Resource socket)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 
Destroy()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.
MMap(void * addr,size_t length,int prot,int flags,size_t offset,void ** out_addr)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.
Read(const HandleAttr & attr,void * buf,size_t count,int * out_bytes)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 
Write(const HandleAttr & attr,const void * buf,size_t count,int * out_bytes)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 
NetInterface()86 NetAddressInterface* SocketNode::NetInterface() {
87   if (filesystem_->ppapi() == NULL)
88     return NULL;
89 
90   return filesystem_->ppapi()->GetNetAddressInterface();
91 }
92 
TCPInterface()93 TCPSocketInterface* SocketNode::TCPInterface() {
94   if (filesystem_->ppapi() == NULL)
95     return NULL;
96 
97   return filesystem_->ppapi()->GetTCPSocketInterface();
98 }
99 
UDPInterface()100 UDPSocketInterface* SocketNode::UDPInterface() {
101   if (filesystem_->ppapi() == NULL)
102     return NULL;
103 
104   return filesystem_->ppapi()->GetUDPSocketInterface();
105 }
106 
SockAddrToResource(const struct sockaddr * addr,socklen_t len)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 
ResourceToSockAddr(PP_Resource addr,socklen_t len,struct sockaddr * out_addr)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 
IsEquivalentAddress(PP_Resource addr1,PP_Resource addr2)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 
Accept(const HandleAttr & attr,PP_Resource * new_sock,struct sockaddr * addr,socklen_t * len)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 
Connect(const HandleAttr & attr,const struct sockaddr * addr,socklen_t len)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 
Listen(int backlog)220 Error SocketNode::Listen(int backlog) {
221   return EOPNOTSUPP;
222 }
223 
GetSockOpt(int lvl,int optname,void * optval,socklen_t * len)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 
SetSockOpt(int lvl,int optname,const void * optval,socklen_t len)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 
Bind(const struct sockaddr * addr,socklen_t len)318 Error SocketNode::Bind(const struct sockaddr* addr, socklen_t len) {
319   return EINVAL;
320 }
321 
Recv(const HandleAttr & attr,void * buf,size_t len,int flags,int * out_len)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 
RecvFrom(const HandleAttr & attr,void * buf,size_t len,int flags,struct sockaddr * src_addr,socklen_t * addrlen,int * out_len)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 
RecvHelper(const HandleAttr & attr,void * buf,size_t len,int flags,PP_Resource * addr,int * out_len)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 
Send(const HandleAttr & attr,const void * buf,size_t len,int flags,int * out_len)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 
SendTo(const HandleAttr & attr,const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen,int * out_len)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 
SendHelper(const HandleAttr & attr,const void * buf,size_t len,int flags,PP_Resource addr,int * out_len)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 
SetError_Locked(int pp_error_num)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 
Shutdown(int how)449 Error SocketNode::Shutdown(int how) {
450   return EOPNOTSUPP;
451 }
452 
GetPeerName(struct sockaddr * addr,socklen_t * len)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 
GetSockName(struct sockaddr * addr,socklen_t * len)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