Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / socket / socket_node.cc
blob5ff6f9dcd32d5d3732af18f022284a1c2b8c84a7
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.
5 #include "nacl_io/socket/socket_node.h"
7 #include "nacl_io/ossocket.h"
8 #ifdef PROVIDES_SOCKET_API
10 #include <errno.h>
11 #include <string.h>
13 #include "nacl_io/filesystem.h"
14 #include "nacl_io/kernel_handle.h"
15 #include "nacl_io/pepper_interface.h"
17 #include "ppapi/c/pp_resource.h"
18 #include "ppapi/c/ppb_net_address.h"
20 namespace nacl_io {
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);
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_);
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_);
55 socket_resource_ = 0;
56 local_addr_ = 0;
57 remote_addr_ = 0;
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;
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);
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);
86 NetAddressInterface* SocketNode::NetInterface() {
87 if (filesystem_->ppapi() == NULL)
88 return NULL;
90 return filesystem_->ppapi()->GetNetAddressInterface();
93 TCPSocketInterface* SocketNode::TCPInterface() {
94 if (filesystem_->ppapi() == NULL)
95 return NULL;
97 return filesystem_->ppapi()->GetTCPSocketInterface();
100 UDPSocketInterface* SocketNode::UDPInterface() {
101 if (filesystem_->ppapi() == NULL)
102 return NULL;
104 return filesystem_->ppapi()->GetUDPSocketInterface();
107 PP_Resource SocketNode::SockAddrToResource(const struct sockaddr* addr,
108 socklen_t len) {
109 if (NULL == addr)
110 return 0;
112 if (AF_INET == addr->sa_family) {
113 const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(addr);
114 return SockAddrInToResource(sin, len);
117 if (AF_INET6 == addr->sa_family) {
118 const sockaddr_in6* sin = reinterpret_cast<const sockaddr_in6*>(addr);
119 return SockAddrIn6ToResource(sin, len);
121 return 0;
124 PP_Resource SocketNode::SockAddrInToResource(const sockaddr_in* sin,
125 socklen_t len) {
126 if (len != sizeof(sockaddr_in))
127 return 0;
129 PP_NetAddress_IPv4 addr4;
130 memset(&addr4, 0, sizeof(addr4));
132 addr4.port = sin->sin_port;
133 memcpy(addr4.addr, &sin->sin_addr, sizeof(addr4.addr));
134 return filesystem_->ppapi()->GetNetAddressInterface()->CreateFromIPv4Address(
135 filesystem_->ppapi()->GetInstance(), &addr4);
138 PP_Resource SocketNode::SockAddrIn6ToResource(const sockaddr_in6* sin,
139 socklen_t len) {
140 if (len != sizeof(sockaddr_in6))
141 return 0;
143 PP_NetAddress_IPv6 addr6;
144 memset(&addr6, 0, sizeof(addr6));
146 addr6.port = sin->sin6_port;
147 memcpy(addr6.addr, &sin->sin6_addr, sizeof(addr6.addr));
148 return filesystem_->ppapi()->GetNetAddressInterface()->CreateFromIPv6Address(
149 filesystem_->ppapi()->GetInstance(), &addr6);
152 socklen_t SocketNode::ResourceToSockAddr(PP_Resource addr,
153 socklen_t len,
154 struct sockaddr* out_addr) {
155 if (0 == addr)
156 return 0;
158 PP_NetAddress_IPv4 ipv4;
159 PP_NetAddress_IPv6 ipv6;
161 if (PP_TRUE == NetInterface()->DescribeAsIPv4Address(addr, &ipv4)) {
162 sockaddr_in addr4;
163 addr4.sin_family = AF_INET;
164 addr4.sin_port = ipv4.port;
165 memcpy(&addr4.sin_addr, ipv4.addr, sizeof(ipv4.addr));
166 memcpy(out_addr, &addr4,
167 std::min(len, static_cast<socklen_t>(sizeof(addr4))));
169 // Returns required size not copied size like getpeername/getsockname.
170 return sizeof(addr4);
173 if (PP_TRUE == NetInterface()->DescribeAsIPv6Address(addr, &ipv6)) {
174 sockaddr_in6 addr6;
175 addr6.sin6_family = AF_INET6;
176 addr6.sin6_port = ipv6.port;
177 memcpy(&addr6.sin6_addr, ipv6.addr, sizeof(ipv6.addr));
178 memcpy(out_addr, &addr6,
179 std::min(len, static_cast<socklen_t>(sizeof(addr6))));
181 // Returns required size not copied size like getpeername/getsockname.
182 return sizeof(addr6);
185 return 0;
188 bool SocketNode::IsEquivalentAddress(PP_Resource addr1, PP_Resource addr2) {
189 if (addr1 == addr2)
190 return true;
192 char data1[sizeof(sockaddr_in6)];
193 char data2[sizeof(sockaddr_in6)];
195 sockaddr* saddr1 = reinterpret_cast<sockaddr*>(data1);
196 sockaddr* saddr2 = reinterpret_cast<sockaddr*>(data2);
198 socklen_t len1 = ResourceToSockAddr(addr1, sizeof(data1), saddr1);
199 socklen_t len2 = ResourceToSockAddr(addr2, sizeof(data2), saddr2);
201 if (len1 != len2)
202 return false;
204 return memcmp(saddr1, saddr2, len1) == 0;
207 Error SocketNode::Accept(const HandleAttr& attr,
208 PP_Resource* new_sock,
209 struct sockaddr* addr,
210 socklen_t* len) {
211 return ENOSYS;
214 Error SocketNode::Connect(const HandleAttr& attr,
215 const struct sockaddr* addr,
216 socklen_t len) {
217 if (len < 1)
218 return EINVAL;
220 if (NULL == addr)
221 return EFAULT;
223 return EOPNOTSUPP;
226 Error SocketNode::Listen(int backlog) {
227 return EOPNOTSUPP;
230 Error SocketNode::GetSockOpt(int lvl,
231 int optname,
232 void* optval,
233 socklen_t* len) {
234 if (lvl != SOL_SOCKET)
235 return ENOPROTOOPT;
237 AUTO_LOCK(node_lock_);
239 int value = 0;
240 socklen_t value_len = 0;
241 void* value_ptr = NULL;
243 switch (optname) {
244 case SO_REUSEADDR:
245 // SO_REUSEADDR is effectively always on since we can't
246 // disable it with PPAPI sockets.
247 value = 1;
248 value_ptr = &value;
249 value_len = sizeof(value);
250 break;
251 case SO_LINGER:
252 value_ptr = &linger_;
253 value_len = sizeof(linger_);
254 break;
255 case SO_KEEPALIVE:
256 value = keep_alive_;
257 value_ptr = &value;
258 value_len = sizeof(value);
259 break;
260 case SO_ERROR:
261 value_ptr = &last_errno_;
262 value_len = sizeof(last_errno_);
263 last_errno_ = 0;
264 break;
265 default:
266 return ENOPROTOOPT;
269 int copy_bytes = std::min(value_len, *len);
270 memcpy(optval, value_ptr, copy_bytes);
271 *len = value_len;
272 return 0;
275 Error SocketNode::SetSockOpt(int lvl,
276 int optname,
277 const void* optval,
278 socklen_t len) {
279 AUTO_LOCK(node_lock_);
281 switch (lvl) {
282 case SOL_SOCKET: {
283 return SetSockOptSocket(optname, optval, len);
285 case IPPROTO_TCP: {
286 return SetSockOptTCP(optname, optval, len);
288 case IPPROTO_IP: {
289 return SetSockOptIP(optname, optval, len);
291 case IPPROTO_IPV6: {
292 return SetSockOptIPV6(optname, optval, len);
294 default: { break; }
297 return ENOPROTOOPT;
300 Error SocketNode::SetSockOptSocket(int optname,
301 const void* optval,
302 socklen_t len) {
303 size_t buflen = static_cast<size_t>(len);
304 switch (optname) {
305 case SO_REUSEADDR: {
306 // SO_REUSEADDR is effectivly always on since we can't
307 // disable it with PPAPI sockets. Just return success
308 // here regardless.
309 if (buflen < sizeof(int))
310 return EINVAL;
311 return 0;
313 case SO_LINGER: {
314 // Not supported by the PPAPI interface but we preserve
315 // the settings and pretend to support it.
316 if (buflen < sizeof(struct linger))
317 return EINVAL;
318 struct linger new_linger = *static_cast<const linger*>(optval);
319 // Don't allow setting linger to be enabled until we
320 // implement the required synchronous shutdown()/close().
321 // TODO(sbc): remove this after http://crbug.com/312401
322 // gets fixed.
323 if (new_linger.l_onoff != 0)
324 return EINVAL;
325 linger_ = new_linger;
326 return 0;
328 case SO_KEEPALIVE: {
329 // Not supported by the PPAPI interface but we preserve
330 // the flag and pretend to support it.
331 if (buflen < sizeof(int))
332 return EINVAL;
333 int value = *static_cast<const int*>(optval);
334 keep_alive_ = value != 0;
335 return 0;
339 return ENOPROTOOPT;
342 Error SocketNode::SetSockOptTCP(int optname,
343 const void* optval,
344 socklen_t len) {
345 return ENOPROTOOPT;
348 Error SocketNode::SetSockOptIP(int optname, const void* optval, socklen_t len) {
349 return ENOPROTOOPT;
352 Error SocketNode::SetSockOptIPV6(int optname,
353 const void* optval,
354 socklen_t len) {
355 return ENOPROTOOPT;
358 Error SocketNode::Bind(const struct sockaddr* addr, socklen_t len) {
359 return EINVAL;
362 Error SocketNode::Recv(const HandleAttr& attr,
363 void* buf,
364 size_t len,
365 int flags,
366 int* out_len) {
367 return RecvFrom(attr, buf, len, flags, NULL, 0, out_len);
370 Error SocketNode::RecvFrom(const HandleAttr& attr,
371 void* buf,
372 size_t len,
373 int flags,
374 struct sockaddr* src_addr,
375 socklen_t* addrlen,
376 int* out_len) {
377 PP_Resource addr = 0;
378 Error err = RecvHelper(attr, buf, len, flags, &addr, out_len);
379 if (0 == err && 0 != addr) {
380 if (src_addr)
381 *addrlen = ResourceToSockAddr(addr, *addrlen, src_addr);
383 filesystem_->ppapi()->ReleaseResource(addr);
386 return err;
389 Error SocketNode::RecvHelper(const HandleAttr& attr,
390 void* buf,
391 size_t len,
392 int flags,
393 PP_Resource* addr,
394 int* out_len) {
395 if (0 == socket_resource_)
396 return EBADF;
398 if (TestStreamFlags(SSF_RECV_ENDOFSTREAM)) {
399 *out_len = 0;
400 return 0;
403 int ms = read_timeout_;
404 if ((flags & MSG_DONTWAIT) || !attr.IsBlocking())
405 ms = 0;
407 // TODO(bradnelson) BUG=295177
408 // For UDP we should support filtering packets when using connect
409 EventListenerLock wait(GetEventEmitter());
410 Error err = wait.WaitOnEvent(POLLIN, ms);
412 // Timeout is treated as a would block for sockets.
413 if (ETIMEDOUT == err)
414 return EWOULDBLOCK;
416 if (err)
417 return err;
419 err = Recv_Locked(buf, len, addr, out_len);
421 // We must have read from then inputbuffer, so Q up some receive work.
422 if ((err == 0) && *out_len)
423 QueueInput();
424 return err;
427 Error SocketNode::Send(const HandleAttr& attr,
428 const void* buf,
429 size_t len,
430 int flags,
431 int* out_len) {
432 return SendHelper(attr, buf, len, flags, remote_addr_, out_len);
435 Error SocketNode::SendTo(const HandleAttr& attr,
436 const void* buf,
437 size_t len,
438 int flags,
439 const struct sockaddr* dest_addr,
440 socklen_t addrlen,
441 int* out_len) {
442 if ((NULL == dest_addr) && (0 == remote_addr_))
443 return EDESTADDRREQ;
445 PP_Resource addr = SockAddrToResource(dest_addr, addrlen);
446 if (0 == addr)
447 return EINVAL;
449 Error err = SendHelper(attr, buf, len, flags, addr, out_len);
450 filesystem_->ppapi()->ReleaseResource(addr);
451 return err;
454 Error SocketNode::SendHelper(const HandleAttr& attr,
455 const void* buf,
456 size_t len,
457 int flags,
458 PP_Resource addr,
459 int* out_len) {
460 if (0 == socket_resource_)
461 return EBADF;
463 if (0 == addr)
464 return ENOTCONN;
466 int ms = write_timeout_;
467 if ((flags & MSG_DONTWAIT) || !attr.IsBlocking())
468 ms = 0;
470 EventListenerLock wait(GetEventEmitter());
471 Error err = wait.WaitOnEvent(POLLOUT, ms);
473 // Timeout is treated as a would block for sockets.
474 if (ETIMEDOUT == err)
475 return EWOULDBLOCK;
477 if (err)
478 return err;
480 err = Send_Locked(buf, len, addr, out_len);
482 // We must have added to the output buffer, so Q up some transmit work.
483 if ((err == 0) && *out_len)
484 QueueOutput();
485 return err;
488 void SocketNode::SetError_Locked(int pp_error_num) {
489 SetStreamFlags(SSF_ERROR | SSF_CLOSED);
490 ClearStreamFlags(SSF_CAN_SEND | SSF_CAN_RECV);
491 last_errno_ = PPERROR_TO_ERRNO(pp_error_num);
494 Error SocketNode::Shutdown(int how) {
495 return EOPNOTSUPP;
498 Error SocketNode::GetPeerName(struct sockaddr* addr, socklen_t* len) {
499 if (NULL == addr || NULL == len)
500 return EFAULT;
502 AUTO_LOCK(node_lock_);
503 if (remote_addr_ != 0) {
504 *len = ResourceToSockAddr(remote_addr_, *len, addr);
505 return 0;
508 return ENOTCONN;
511 Error SocketNode::GetSockName(struct sockaddr* addr, socklen_t* len) {
512 if (NULL == addr || NULL == len)
513 return EFAULT;
515 AUTO_LOCK(node_lock_);
516 if (local_addr_ == 0) {
517 // getsockname succeeds even if the socket is not bound. In this case,
518 // just return address 0, port 0.
519 memset(addr, 0, *len);
520 return 0;
523 *len = ResourceToSockAddr(local_addr_, *len, addr);
524 return 0;
527 } // namespace nacl_io
529 #endif // PROVIDES_SOCKET_API