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