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/udp_node.h"
12 #include "nacl_io/log.h"
13 #include "nacl_io/pepper_interface.h"
14 #include "nacl_io/socket/packet.h"
15 #include "nacl_io/socket/udp_event_emitter.h"
16 #include "nacl_io/stream/stream_fs.h"
19 const size_t kMaxPacketSize
= 65536;
20 const size_t kDefaultFifoSize
= kMaxPacketSize
* 8;
25 class UdpWork
: public StreamFs::Work
{
27 explicit UdpWork(const ScopedUdpEventEmitter
& emitter
)
28 : StreamFs::Work(emitter
->stream()->stream()),
32 ~UdpWork() { delete packet_
; }
34 UDPSocketInterface
* UDPInterface() {
35 return filesystem()->ppapi()->GetUDPSocketInterface();
39 ScopedUdpEventEmitter emitter_
;
43 class UdpSendWork
: public UdpWork
{
45 explicit UdpSendWork(const ScopedUdpEventEmitter
& emitter
,
46 const ScopedSocketNode
& node
)
47 : UdpWork(emitter
), node_(node
) {}
49 virtual bool Start(int32_t val
) {
50 AUTO_LOCK(emitter_
->GetLock());
52 // Does the stream exist, and can it send?
53 if (!node_
->TestStreamFlags(SSF_CAN_SEND
))
56 // Check if we are already sending.
57 if (node_
->TestStreamFlags(SSF_SENDING
))
60 // If this is a retry packet, packet_ will be already set
61 // and we don't need to dequeue from emitter_.
62 if (NULL
== packet_
) {
63 packet_
= emitter_
->ReadTXPacket_Locked();
68 int err
= UDPInterface()->SendTo(node_
->socket_resource(),
72 filesystem()->GetRunCompletion(this));
73 if (err
!= PP_OK_COMPLETIONPENDING
) {
74 // Anything else, we should assume the socket has gone bad.
75 node_
->SetError_Locked(err
);
79 node_
->SetStreamFlags(SSF_SENDING
);
83 virtual void Run(int32_t length_error
) {
84 AUTO_LOCK(emitter_
->GetLock());
86 if (length_error
< 0) {
87 if (length_error
== PP_ERROR_INPROGRESS
) {
88 // We need to retry this packet later.
89 node_
->ClearStreamFlags(SSF_SENDING
);
90 node_
->stream()->EnqueueWork(this);
93 node_
->SetError_Locked(length_error
);
97 // If we did send, then Q more work.
98 node_
->ClearStreamFlags(SSF_SENDING
);
103 // We assume that transmits will always complete. If the upstream
104 // actually back pressures, enough to prevent the Send callback
105 // from triggering, this resource may never go away.
106 ScopedSocketNode node_
;
109 class UdpRecvWork
: public UdpWork
{
111 explicit UdpRecvWork(const ScopedUdpEventEmitter
& emitter
)
115 virtual bool Start(int32_t val
) {
116 AUTO_LOCK(emitter_
->GetLock());
117 UdpNode
* stream
= static_cast<UdpNode
*>(emitter_
->stream());
119 // Does the stream exist, and can it recv?
120 if (NULL
== stream
|| !stream
->TestStreamFlags(SSF_CAN_RECV
))
123 // Check if we are already receiving.
124 if (stream
->TestStreamFlags(SSF_RECVING
))
127 stream
->SetStreamFlags(SSF_RECVING
);
128 int err
= UDPInterface()->RecvFrom(stream
->socket_resource(),
132 filesystem()->GetRunCompletion(this));
133 if (err
!= PP_OK_COMPLETIONPENDING
) {
134 stream
->SetError_Locked(err
);
141 virtual void Run(int32_t length_error
) {
142 AUTO_LOCK(emitter_
->GetLock());
143 UdpNode
* stream
= static_cast<UdpNode
*>(emitter_
->stream());
147 // On successful receive we queue more input
148 if (length_error
> 0) {
149 Packet
* packet
= new Packet(filesystem()->ppapi());
150 packet
->Copy(data_
, length_error
, addr_
);
151 filesystem()->ppapi()->ReleaseResource(addr_
);
152 emitter_
->WriteRXPacket_Locked(packet
);
153 stream
->ClearStreamFlags(SSF_RECVING
);
154 stream
->QueueInput();
156 stream
->SetError_Locked(length_error
);
161 char data_
[kMaxPacketSize
];
165 UdpNode::UdpNode(Filesystem
* filesystem
)
166 : SocketNode(filesystem
),
167 emitter_(new UdpEventEmitter(kDefaultFifoSize
, kDefaultFifoSize
)) {
168 emitter_
->AttachStream(this);
171 void UdpNode::Destroy() {
172 emitter_
->DetachStream();
173 SocketNode::Destroy();
176 UdpEventEmitter
* UdpNode::GetEventEmitter() {
177 return emitter_
.get();
180 Error
UdpNode::Init(int open_flags
) {
181 Error err
= SocketNode::Init(open_flags
);
185 if (UDPInterface() == NULL
) {
186 LOG_ERROR("Got NULL interface: UDP");
191 UDPInterface()->Create(filesystem_
->ppapi()->GetInstance());
192 if (0 == socket_resource_
) {
193 LOG_ERROR("Unable to create UDP resource.");
200 void UdpNode::QueueInput() {
201 UdpRecvWork
* work
= new UdpRecvWork(emitter_
);
202 stream()->EnqueueWork(work
);
205 void UdpNode::QueueOutput() {
206 if (!TestStreamFlags(SSF_CAN_SEND
))
209 if (TestStreamFlags(SSF_SENDING
))
212 UdpSendWork
* work
= new UdpSendWork(emitter_
, ScopedSocketNode(this));
213 stream()->EnqueueWork(work
);
216 Error
UdpNode::Bind(const struct sockaddr
* addr
, socklen_t len
) {
217 if (0 == socket_resource_
)
220 /* Only bind once. */
224 PP_Resource out_addr
= SockAddrToResource(addr
, len
);
229 UDPInterface()->Bind(socket_resource_
, out_addr
, PP_BlockUntilComplete());
230 filesystem_
->ppapi()->ReleaseResource(out_addr
);
232 return PPERROR_TO_ERRNO(err
);
234 // Get the address that was actually bound (in case addr was 0.0.0.0:0).
235 out_addr
= UDPInterface()->GetBoundAddress(socket_resource_
);
239 // Now that we are bound, we can start sending and receiving.
240 SetStreamFlags(SSF_CAN_SEND
| SSF_CAN_RECV
);
243 local_addr_
= out_addr
;
247 Error
UdpNode::Connect(const HandleAttr
& attr
,
248 const struct sockaddr
* addr
,
250 if (0 == socket_resource_
)
253 /* Connect for UDP is the default dest, it's legal to change it. */
254 if (remote_addr_
!= 0) {
255 filesystem_
->ppapi()->ReleaseResource(remote_addr_
);
259 remote_addr_
= SockAddrToResource(addr
, len
);
260 if (0 == remote_addr_
)
266 Error
UdpNode::Recv_Locked(void* buf
,
268 PP_Resource
* out_addr
,
270 Packet
* packet
= emitter_
->ReadRXPacket_Locked();
275 int capped_len
= static_cast<int32_t>(std::min
<int>(len
, packet
->len()));
276 memcpy(buf
, packet
->buffer(), capped_len
);
278 if (packet
->addr() != 0) {
279 filesystem_
->ppapi()->AddRefResource(packet
->addr());
280 *out_addr
= packet
->addr();
283 *out_len
= capped_len
;
288 // Should never happen, Recv_Locked should not be called
289 // unless already in a POLLIN state.
293 Error
UdpNode::Send_Locked(const void* buf
,
298 // Pepper requires a socket to be bound before it can send.
300 addr
.sin_family
= AF_INET
;
302 memset(&addr
.sin_addr
, 0, sizeof(addr
.sin_addr
));
304 Bind(reinterpret_cast<const struct sockaddr
*>(&addr
), sizeof(addr
));
310 int capped_len
= static_cast<int32_t>(std::min
<int>(len
, kMaxPacketSize
));
311 Packet
* packet
= new Packet(filesystem_
->ppapi());
312 packet
->Copy(buf
, capped_len
, addr
);
314 emitter_
->WriteTXPacket_Locked(packet
);
315 *out_len
= capped_len
;
319 Error
UdpNode::SetSockOptSocket(int optname
,
322 if (static_cast<size_t>(len
) < sizeof(int))
327 int bufsize
= *static_cast<const int*>(optval
);
328 int32_t error
= UDPInterface()->SetOption(
329 socket_resource_
, PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE
,
330 PP_MakeInt32(bufsize
), PP_BlockUntilComplete());
331 return PPERROR_TO_ERRNO(error
);
334 int bufsize
= *static_cast<const int*>(optval
);
335 int32_t error
= UDPInterface()->SetOption(
336 socket_resource_
, PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE
,
337 PP_MakeInt32(bufsize
), PP_BlockUntilComplete());
338 return PPERROR_TO_ERRNO(error
);
341 int broadcast
= *static_cast<const int*>(optval
);
342 int32_t error
= UDPInterface()->SetOption(
343 socket_resource_
, PP_UDPSOCKET_OPTION_BROADCAST
,
344 PP_MakeBool(broadcast
? PP_TRUE
: PP_FALSE
), PP_BlockUntilComplete());
345 return PPERROR_TO_ERRNO(error
);
350 return SocketNode::SetSockOptSocket(optname
, optval
, len
);
353 Error
UdpNode::SetSockOptIP(int optname
, const void* optval
, socklen_t len
) {
354 if (static_cast<size_t>(len
) < sizeof(int))
358 case IP_MULTICAST_LOOP
: {
359 int loop
= *static_cast<const int*>(optval
);
360 int32_t error
= UDPInterface()->SetOption(
361 socket_resource_
, PP_UDPSOCKET_OPTION_MULTICAST_LOOP
,
362 PP_MakeBool(loop
? PP_TRUE
: PP_FALSE
), PP_BlockUntilComplete());
363 return PPERROR_TO_ERRNO(error
);
365 case IP_MULTICAST_TTL
: {
366 unsigned int ttl
= *static_cast<const unsigned int*>(optval
);
367 int32_t error
= UDPInterface()->SetOption(
368 socket_resource_
, PP_UDPSOCKET_OPTION_MULTICAST_TTL
,
369 PP_MakeInt32(ttl
), PP_BlockUntilComplete());
370 return PPERROR_TO_ERRNO(error
);
372 case IP_MULTICAST_IF
: {
373 // PPAPI does not expose this option, but we pretend to support it.
374 // TODO(etrunko): store value to be returned by GetSockOpt() when it is
378 case IP_ADD_MEMBERSHIP
: {
379 const struct ip_mreq
* mreq
= static_cast<const struct ip_mreq
*>(optval
);
380 struct sockaddr_in sin
= {0};
381 sin
.sin_family
= AF_INET
;
382 memcpy(&sin
.sin_addr
, &mreq
->imr_multiaddr
, sizeof(struct in_addr
));
384 PP_Resource net_addr
= SockAddrInToResource(&sin
, sizeof(sin
));
385 int32_t error
= UDPInterface()->JoinGroup(socket_resource_
, net_addr
,
386 PP_BlockUntilComplete());
387 return PPERROR_TO_ERRNO(error
);
389 case IP_DROP_MEMBERSHIP
: {
390 const struct ip_mreq
* mreq
= static_cast<const struct ip_mreq
*>(optval
);
391 struct sockaddr_in sin
= {0};
392 sin
.sin_family
= AF_INET
;
393 memcpy(&sin
.sin_addr
, &mreq
->imr_multiaddr
, sizeof(struct in_addr
));
395 PP_Resource net_addr
= SockAddrInToResource(&sin
, sizeof(sin
));
396 int32_t error
= UDPInterface()->LeaveGroup(socket_resource_
, net_addr
,
397 PP_BlockUntilComplete());
398 return PPERROR_TO_ERRNO(error
);
403 return SocketNode::SetSockOptIP(optname
, optval
, len
);
406 Error
UdpNode::SetSockOptIPV6(int optname
, const void* optval
, socklen_t len
) {
407 if (static_cast<size_t>(len
) < sizeof(int))
411 case IPV6_MULTICAST_LOOP
: {
412 int loop
= *static_cast<const int*>(optval
);
413 int32_t error
= UDPInterface()->SetOption(
414 socket_resource_
, PP_UDPSOCKET_OPTION_MULTICAST_LOOP
,
415 PP_MakeBool(loop
? PP_TRUE
: PP_FALSE
), PP_BlockUntilComplete());
416 return PPERROR_TO_ERRNO(error
);
418 case IPV6_MULTICAST_HOPS
: {
419 unsigned int ttl
= *static_cast<const unsigned int*>(optval
);
420 int32_t error
= UDPInterface()->SetOption(
421 socket_resource_
, PP_UDPSOCKET_OPTION_MULTICAST_TTL
,
422 PP_MakeInt32(ttl
), PP_BlockUntilComplete());
423 return PPERROR_TO_ERRNO(error
);
425 case IPV6_MULTICAST_IF
: {
426 // PPAPI does not expose this option, but we pretend to support it.
427 // TODO(etrunko): store value to be returned by GetSockOpt() when it is
431 case IPV6_JOIN_GROUP
: {
432 const struct ipv6_mreq
* mreq
=
433 static_cast<const struct ipv6_mreq
*>(optval
);
434 struct sockaddr_in6 sin
= {0};
435 sin
.sin6_family
= AF_INET6
;
436 memcpy(&sin
.sin6_addr
, &mreq
->ipv6mr_multiaddr
, sizeof(struct in6_addr
));
438 PP_Resource net_addr
= SockAddrIn6ToResource(&sin
, sizeof(sin
));
439 int32_t error
= UDPInterface()->LeaveGroup(socket_resource_
, net_addr
,
440 PP_BlockUntilComplete());
441 return PPERROR_TO_ERRNO(error
);
443 case IPV6_LEAVE_GROUP
: {
444 const struct ipv6_mreq
* mreq
=
445 static_cast<const struct ipv6_mreq
*>(optval
);
446 struct sockaddr_in6 sin
= {0};
447 sin
.sin6_family
= AF_INET6
;
448 memcpy(&sin
.sin6_addr
, &mreq
->ipv6mr_multiaddr
, sizeof(struct in6_addr
));
450 PP_Resource net_addr
= SockAddrIn6ToResource(&sin
, sizeof(sin
));
451 int32_t error
= UDPInterface()->LeaveGroup(socket_resource_
, net_addr
,
452 PP_BlockUntilComplete());
453 return PPERROR_TO_ERRNO(error
);
458 return SocketNode::SetSockOptIPV6(optname
, optval
, len
);
461 } // namespace nacl_io