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 PP_NetAddress_IPv4 addr4
;
114 const sockaddr_in
* sin
= reinterpret_cast<const sockaddr_in
*>(addr
);
116 if (len
!= sizeof(sockaddr_in
))
119 memset(&addr4
, 0, sizeof(addr4
));
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
);
128 if (AF_INET6
== addr
->sa_family
) {
129 PP_NetAddress_IPv6 addr6
;
130 const sockaddr_in6
* sin
= reinterpret_cast<const sockaddr_in6
*>(addr
);
132 if (len
!= sizeof(sockaddr_in6
))
135 memset(&addr6
, 0, sizeof(addr6
));
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
);
146 socklen_t
SocketNode::ResourceToSockAddr(PP_Resource addr
,
148 struct sockaddr
* out_addr
) {
152 PP_NetAddress_IPv4 ipv4
;
153 PP_NetAddress_IPv6 ipv6
;
155 if (PP_TRUE
== NetInterface()->DescribeAsIPv4Address(addr
, &ipv4
)) {
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
))));
163 // Returns required size not copied size like getpeername/getsockname.
164 return sizeof(addr4
);
167 if (PP_TRUE
== NetInterface()->DescribeAsIPv6Address(addr
, &ipv6
)) {
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
))));
175 // Returns required size not copied size like getpeername/getsockname.
176 return sizeof(addr6
);
182 bool SocketNode::IsEquivalentAddress(PP_Resource addr1
, PP_Resource addr2
) {
186 char data1
[sizeof(sockaddr_in6
)];
187 char data2
[sizeof(sockaddr_in6
)];
189 sockaddr
* saddr1
= reinterpret_cast<sockaddr
*>(data1
);
190 sockaddr
* saddr2
= reinterpret_cast<sockaddr
*>(data2
);
192 socklen_t len1
= ResourceToSockAddr(addr1
, sizeof(data1
), saddr1
);
193 socklen_t len2
= ResourceToSockAddr(addr2
, sizeof(data2
), saddr2
);
198 return memcmp(saddr1
, saddr2
, len1
) == 0;
201 Error
SocketNode::Accept(const HandleAttr
& attr
,
202 PP_Resource
* new_sock
,
203 struct sockaddr
* addr
,
208 Error
SocketNode::Connect(const HandleAttr
& attr
,
209 const struct sockaddr
* addr
,
220 Error
SocketNode::Listen(int backlog
) {
224 Error
SocketNode::GetSockOpt(int lvl
,
228 if (lvl
!= SOL_SOCKET
)
231 AUTO_LOCK(node_lock_
);
234 socklen_t value_len
= 0;
235 void* value_ptr
= NULL
;
239 // SO_REUSEADDR is effectively always on since we can't
240 // disable it with PPAPI sockets.
243 value_len
= sizeof(value
);
246 value_ptr
= &linger_
;
247 value_len
= sizeof(linger_
);
252 value_len
= sizeof(value
);
255 value_ptr
= &last_errno_
;
256 value_len
= sizeof(last_errno_
);
263 int copy_bytes
= std::min(value_len
, *len
);
264 memcpy(optval
, value_ptr
, copy_bytes
);
269 Error
SocketNode::SetSockOpt(int lvl
,
273 size_t buflen
= static_cast<size_t>(len
);
275 if (lvl
!= SOL_SOCKET
)
278 AUTO_LOCK(node_lock_
);
282 // SO_REUSEADDR is effectivly always on since we can't
283 // disable it with PPAPI sockets. Just return success
285 if (buflen
< sizeof(int))
290 // Not supported by the PPAPI interface but we preserve
291 // the settings and pretend to support it.
292 if (buflen
< sizeof(struct linger
))
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
299 if (new_linger
.l_onoff
!= 0)
301 linger_
= new_linger
;
305 // Not supported by the PPAPI interface but we preserve
306 // the flag and pretend to support it.
307 if (buflen
< sizeof(int))
309 int value
= *static_cast<const int*>(optval
);
310 keep_alive_
= value
!= 0;
318 Error
SocketNode::Bind(const struct sockaddr
* addr
, socklen_t len
) {
322 Error
SocketNode::Recv(const HandleAttr
& attr
,
327 return RecvFrom(attr
, buf
, len
, flags
, NULL
, 0, out_len
);
330 Error
SocketNode::RecvFrom(const HandleAttr
& attr
,
334 struct sockaddr
* src_addr
,
337 PP_Resource addr
= 0;
338 Error err
= RecvHelper(attr
, buf
, len
, flags
, &addr
, out_len
);
339 if (0 == err
&& 0 != addr
) {
341 *addrlen
= ResourceToSockAddr(addr
, *addrlen
, src_addr
);
343 filesystem_
->ppapi()->ReleaseResource(addr
);
349 Error
SocketNode::RecvHelper(const HandleAttr
& attr
,
355 if (0 == socket_resource_
)
358 if (TestStreamFlags(SSF_RECV_ENDOFSTREAM
)) {
363 int ms
= read_timeout_
;
364 if ((flags
& MSG_DONTWAIT
) || !attr
.IsBlocking())
367 // TODO(bradnelson) BUG=295177
368 // For UDP we should support filtering packets when using connect
369 EventListenerLock
wait(GetEventEmitter());
370 Error err
= wait
.WaitOnEvent(POLLIN
, ms
);
372 // Timeout is treated as a would block for sockets.
373 if (ETIMEDOUT
== err
)
379 err
= Recv_Locked(buf
, len
, addr
, out_len
);
381 // We must have read from then inputbuffer, so Q up some receive work.
382 if ((err
== 0) && *out_len
)
387 Error
SocketNode::Send(const HandleAttr
& attr
,
392 return SendHelper(attr
, buf
, len
, flags
, remote_addr_
, out_len
);
395 Error
SocketNode::SendTo(const HandleAttr
& attr
,
399 const struct sockaddr
* dest_addr
,
402 if ((NULL
== dest_addr
) && (0 == remote_addr_
))
405 PP_Resource addr
= SockAddrToResource(dest_addr
, addrlen
);
409 Error err
= SendHelper(attr
, buf
, len
, flags
, addr
, out_len
);
410 filesystem_
->ppapi()->ReleaseResource(addr
);
414 Error
SocketNode::SendHelper(const HandleAttr
& attr
,
420 if (0 == socket_resource_
)
426 int ms
= write_timeout_
;
427 if ((flags
& MSG_DONTWAIT
) || !attr
.IsBlocking())
430 EventListenerLock
wait(GetEventEmitter());
431 Error err
= wait
.WaitOnEvent(POLLOUT
, ms
);
433 // Timeout is treated as a would block for sockets.
434 if (ETIMEDOUT
== err
)
440 err
= Send_Locked(buf
, len
, addr
, out_len
);
442 // We must have added to the output buffer, so Q up some transmit work.
443 if ((err
== 0) && *out_len
)
448 void SocketNode::SetError_Locked(int pp_error_num
) {
449 SetStreamFlags(SSF_ERROR
| SSF_CLOSED
);
450 ClearStreamFlags(SSF_CAN_SEND
| SSF_CAN_RECV
);
451 last_errno_
= PPErrorToErrno(pp_error_num
);
454 Error
SocketNode::Shutdown(int how
) {
458 Error
SocketNode::GetPeerName(struct sockaddr
* addr
, socklen_t
* len
) {
459 if (NULL
== addr
|| NULL
== len
)
462 AUTO_LOCK(node_lock_
);
463 if (remote_addr_
!= 0) {
464 *len
= ResourceToSockAddr(remote_addr_
, *len
, addr
);
471 Error
SocketNode::GetSockName(struct sockaddr
* addr
, socklen_t
* len
) {
472 if (NULL
== addr
|| NULL
== len
)
475 AUTO_LOCK(node_lock_
);
476 if (local_addr_
== 0) {
477 // getsockname succeeds even if the socket is not bound. In this case,
478 // just return address 0, port 0.
479 memset(addr
, 0, *len
);
483 *len
= ResourceToSockAddr(local_addr_
, *len
, addr
);
487 } // namespace nacl_io
489 #endif // PROVIDES_SOCKET_API