Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / socket / udp_node.cc
blob604c99fb9aacd2b9b9d26a6dda8646f8c87bf113
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"
7 #include <errno.h>
8 #include <string.h>
10 #include <algorithm>
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"
18 namespace {
19 const size_t kMaxPacketSize = 65536;
20 const size_t kDefaultFifoSize = kMaxPacketSize * 8;
23 namespace nacl_io {
25 class UdpWork : public StreamFs::Work {
26 public:
27 explicit UdpWork(const ScopedUdpEventEmitter& emitter)
28 : StreamFs::Work(emitter->stream()->stream()),
29 emitter_(emitter),
30 packet_(NULL) {}
32 ~UdpWork() { delete packet_; }
34 UDPSocketInterface* UDPInterface() {
35 return filesystem()->ppapi()->GetUDPSocketInterface();
38 protected:
39 ScopedUdpEventEmitter emitter_;
40 Packet* packet_;
43 class UdpSendWork : public UdpWork {
44 public:
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))
54 return false;
56 // Check if we are already sending.
57 if (node_->TestStreamFlags(SSF_SENDING))
58 return false;
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();
64 if (NULL == packet_)
65 return false;
68 int err = UDPInterface()->SendTo(node_->socket_resource(),
69 packet_->buffer(),
70 packet_->len(),
71 packet_->addr(),
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);
76 return false;
79 node_->SetStreamFlags(SSF_SENDING);
80 return true;
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);
91 return;
93 node_->SetError_Locked(length_error);
94 return;
97 // If we did send, then Q more work.
98 node_->ClearStreamFlags(SSF_SENDING);
99 node_->QueueOutput();
102 private:
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 {
110 public:
111 explicit UdpRecvWork(const ScopedUdpEventEmitter& emitter)
112 : UdpWork(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))
121 return false;
123 // Check if we are already receiving.
124 if (stream->TestStreamFlags(SSF_RECVING))
125 return false;
127 stream->SetStreamFlags(SSF_RECVING);
128 int err = UDPInterface()->RecvFrom(stream->socket_resource(),
129 data_,
130 kMaxPacketSize,
131 &addr_,
132 filesystem()->GetRunCompletion(this));
133 if (err != PP_OK_COMPLETIONPENDING) {
134 stream->SetError_Locked(err);
135 return false;
138 return true;
141 virtual void Run(int32_t length_error) {
142 AUTO_LOCK(emitter_->GetLock());
143 UdpNode* stream = static_cast<UdpNode*>(emitter_->stream());
144 if (NULL == stream)
145 return;
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();
155 } else {
156 stream->SetError_Locked(length_error);
160 private:
161 char data_[kMaxPacketSize];
162 PP_Resource addr_;
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);
182 if (err != 0)
183 return err;
185 if (UDPInterface() == NULL) {
186 LOG_ERROR("Got NULL interface: UDP");
187 return EACCES;
190 socket_resource_ =
191 UDPInterface()->Create(filesystem_->ppapi()->GetInstance());
192 if (0 == socket_resource_) {
193 LOG_ERROR("Unable to create UDP resource.");
194 return EACCES;
197 return 0;
200 void UdpNode::QueueInput() {
201 UdpRecvWork* work = new UdpRecvWork(emitter_);
202 stream()->EnqueueWork(work);
205 void UdpNode::QueueOutput() {
206 if (!TestStreamFlags(SSF_CAN_SEND))
207 return;
209 if (TestStreamFlags(SSF_SENDING))
210 return;
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_)
218 return EBADF;
220 /* Only bind once. */
221 if (IsBound())
222 return EINVAL;
224 PP_Resource out_addr = SockAddrToResource(addr, len);
225 if (0 == out_addr)
226 return EINVAL;
228 int err =
229 UDPInterface()->Bind(socket_resource_, out_addr, PP_BlockUntilComplete());
230 filesystem_->ppapi()->ReleaseResource(out_addr);
231 if (err != 0)
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_);
236 if (out_addr == 0)
237 return EINVAL;
239 // Now that we are bound, we can start sending and receiving.
240 SetStreamFlags(SSF_CAN_SEND | SSF_CAN_RECV);
241 QueueInput();
243 local_addr_ = out_addr;
244 return 0;
247 Error UdpNode::Connect(const HandleAttr& attr,
248 const struct sockaddr* addr,
249 socklen_t len) {
250 if (0 == socket_resource_)
251 return EBADF;
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_);
256 remote_addr_ = 0;
259 remote_addr_ = SockAddrToResource(addr, len);
260 if (0 == remote_addr_)
261 return EINVAL;
263 return 0;
266 Error UdpNode::Recv_Locked(void* buf,
267 size_t len,
268 PP_Resource* out_addr,
269 int* out_len) {
270 Packet* packet = emitter_->ReadRXPacket_Locked();
271 *out_len = 0;
272 *out_addr = 0;
274 if (packet) {
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;
284 delete packet;
285 return 0;
288 // Should never happen, Recv_Locked should not be called
289 // unless already in a POLLIN state.
290 return EBADF;
293 Error UdpNode::Send_Locked(const void* buf,
294 size_t len,
295 PP_Resource addr,
296 int* out_len) {
297 if (!IsBound()) {
298 // Pepper requires a socket to be bound before it can send.
299 sockaddr_in addr;
300 addr.sin_family = AF_INET;
301 addr.sin_port = 0;
302 memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
303 Error err =
304 Bind(reinterpret_cast<const struct sockaddr*>(&addr), sizeof(addr));
305 if (err != 0)
306 return err;
309 *out_len = 0;
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;
316 return 0;
319 Error UdpNode::SetSockOptSocket(int optname,
320 const void* optval,
321 socklen_t len) {
322 if (static_cast<size_t>(len) < sizeof(int))
323 return EINVAL;
325 switch (optname) {
326 case SO_RCVBUF: {
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);
333 case SO_SNDBUF: {
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);
340 case SO_BROADCAST: {
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);
347 default: { break; }
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))
355 return EINVAL;
357 switch (optname) {
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
375 // implemented.
376 return 0;
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);
400 default: { break; }
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))
408 return EINVAL;
410 switch (optname) {
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
428 // implemented.
429 return 0;
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);
455 default: { break; }
458 return SocketNode::SetSockOptIPV6(optname, optval, len);
461 } // namespace nacl_io