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
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"
22 SocketNode::SocketNode(Filesystem
* filesystem
)
23 : StreamNode(filesystem
),
30 memset(&linger_
, 0, sizeof(linger_
));
34 SocketNode::SocketNode(Filesystem
* filesystem
, PP_Resource socket
)
35 : StreamNode(filesystem
),
36 socket_resource_(socket
),
42 memset(&linger_
, 0, sizeof(linger_
));
44 filesystem_
->ppapi()->AddRefResource(socket_resource_
);
47 void SocketNode::Destroy() {
49 filesystem_
->ppapi()->ReleaseResource(socket_resource_
);
51 filesystem_
->ppapi()->ReleaseResource(local_addr_
);
53 filesystem_
->ppapi()->ReleaseResource(remote_addr_
);
60 // Assume that |addr| and |out_addr| are non-NULL.
61 Error
SocketNode::MMap(void* addr
,
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
,
76 return Recv(attr
, buf
, count
, 0, out_bytes
);
79 Error
SocketNode::Write(const HandleAttr
& attr
,
83 return Send(attr
, buf
, count
, 0, out_bytes
);
86 NetAddressInterface
* SocketNode::NetInterface() {
87 if (filesystem_
->ppapi() == NULL
)
90 return filesystem_
->ppapi()->GetNetAddressInterface();
93 TCPSocketInterface
* SocketNode::TCPInterface() {
94 if (filesystem_
->ppapi() == NULL
)
97 return filesystem_
->ppapi()->GetTCPSocketInterface();
100 UDPSocketInterface
* SocketNode::UDPInterface() {
101 if (filesystem_
->ppapi() == NULL
)
104 return filesystem_
->ppapi()->GetUDPSocketInterface();
107 PP_Resource
SocketNode::SockAddrToResource(const struct sockaddr
* addr
,
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
);
124 PP_Resource
SocketNode::SockAddrInToResource(const sockaddr_in
* sin
,
126 if (len
!= sizeof(sockaddr_in
))
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
,
140 if (len
!= sizeof(sockaddr_in6
))
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
,
154 struct sockaddr
* out_addr
) {
158 PP_NetAddress_IPv4 ipv4
;
159 PP_NetAddress_IPv6 ipv6
;
161 if (PP_TRUE
== NetInterface()->DescribeAsIPv4Address(addr
, &ipv4
)) {
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
)) {
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
);
188 bool SocketNode::IsEquivalentAddress(PP_Resource addr1
, PP_Resource addr2
) {
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
);
204 return memcmp(saddr1
, saddr2
, len1
) == 0;
207 Error
SocketNode::Accept(const HandleAttr
& attr
,
208 PP_Resource
* new_sock
,
209 struct sockaddr
* addr
,
214 Error
SocketNode::Connect(const HandleAttr
& attr
,
215 const struct sockaddr
* addr
,
226 Error
SocketNode::Listen(int backlog
) {
230 Error
SocketNode::GetSockOpt(int lvl
,
234 if (lvl
!= SOL_SOCKET
)
237 AUTO_LOCK(node_lock_
);
240 socklen_t value_len
= 0;
241 void* value_ptr
= NULL
;
245 // SO_REUSEADDR is effectively always on since we can't
246 // disable it with PPAPI sockets.
249 value_len
= sizeof(value
);
252 value_ptr
= &linger_
;
253 value_len
= sizeof(linger_
);
258 value_len
= sizeof(value
);
261 value_ptr
= &last_errno_
;
262 value_len
= sizeof(last_errno_
);
269 int copy_bytes
= std::min(value_len
, *len
);
270 memcpy(optval
, value_ptr
, copy_bytes
);
275 Error
SocketNode::SetSockOpt(int lvl
,
279 AUTO_LOCK(node_lock_
);
283 return SetSockOptSocket(optname
, optval
, len
);
286 return SetSockOptTCP(optname
, optval
, len
);
289 return SetSockOptIP(optname
, optval
, len
);
292 return SetSockOptIPV6(optname
, optval
, len
);
300 Error
SocketNode::SetSockOptSocket(int optname
,
303 size_t buflen
= static_cast<size_t>(len
);
306 // SO_REUSEADDR is effectivly always on since we can't
307 // disable it with PPAPI sockets. Just return success
309 if (buflen
< sizeof(int))
314 // Not supported by the PPAPI interface but we preserve
315 // the settings and pretend to support it.
316 if (buflen
< sizeof(struct linger
))
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
323 if (new_linger
.l_onoff
!= 0)
325 linger_
= new_linger
;
329 // Not supported by the PPAPI interface but we preserve
330 // the flag and pretend to support it.
331 if (buflen
< sizeof(int))
333 int value
= *static_cast<const int*>(optval
);
334 keep_alive_
= value
!= 0;
342 Error
SocketNode::SetSockOptTCP(int optname
,
348 Error
SocketNode::SetSockOptIP(int optname
, const void* optval
, socklen_t len
) {
352 Error
SocketNode::SetSockOptIPV6(int optname
,
358 Error
SocketNode::Bind(const struct sockaddr
* addr
, socklen_t len
) {
362 Error
SocketNode::Recv(const HandleAttr
& attr
,
367 return RecvFrom(attr
, buf
, len
, flags
, NULL
, 0, out_len
);
370 Error
SocketNode::RecvFrom(const HandleAttr
& attr
,
374 struct sockaddr
* src_addr
,
377 PP_Resource addr
= 0;
378 Error err
= RecvHelper(attr
, buf
, len
, flags
, &addr
, out_len
);
379 if (0 == err
&& 0 != addr
) {
381 *addrlen
= ResourceToSockAddr(addr
, *addrlen
, src_addr
);
383 filesystem_
->ppapi()->ReleaseResource(addr
);
389 Error
SocketNode::RecvHelper(const HandleAttr
& attr
,
395 if (0 == socket_resource_
)
398 if (TestStreamFlags(SSF_RECV_ENDOFSTREAM
)) {
403 int ms
= read_timeout_
;
404 if ((flags
& MSG_DONTWAIT
) || !attr
.IsBlocking())
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
)
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
)
427 Error
SocketNode::Send(const HandleAttr
& attr
,
432 return SendHelper(attr
, buf
, len
, flags
, remote_addr_
, out_len
);
435 Error
SocketNode::SendTo(const HandleAttr
& attr
,
439 const struct sockaddr
* dest_addr
,
442 if ((NULL
== dest_addr
) && (0 == remote_addr_
))
445 PP_Resource addr
= SockAddrToResource(dest_addr
, addrlen
);
449 Error err
= SendHelper(attr
, buf
, len
, flags
, addr
, out_len
);
450 filesystem_
->ppapi()->ReleaseResource(addr
);
454 Error
SocketNode::SendHelper(const HandleAttr
& attr
,
460 if (0 == socket_resource_
)
466 int ms
= write_timeout_
;
467 if ((flags
& MSG_DONTWAIT
) || !attr
.IsBlocking())
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
)
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
)
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
) {
498 Error
SocketNode::GetPeerName(struct sockaddr
* addr
, socklen_t
* len
) {
499 if (NULL
== addr
|| NULL
== len
)
502 AUTO_LOCK(node_lock_
);
503 if (remote_addr_
!= 0) {
504 *len
= ResourceToSockAddr(remote_addr_
, *len
, addr
);
511 Error
SocketNode::GetSockName(struct sockaddr
* addr
, socklen_t
* len
) {
512 if (NULL
== addr
|| NULL
== len
)
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
);
523 *len
= ResourceToSockAddr(local_addr_
, *len
, addr
);
527 } // namespace nacl_io
529 #endif // PROVIDES_SOCKET_API