diff options
Diffstat (limited to 'native_client_sdk/src')
10 files changed, 146 insertions, 32 deletions
diff --git a/native_client_sdk/src/libraries/nacl_io/fifo_char.h b/native_client_sdk/src/libraries/nacl_io/fifo_char.h index 27cec2f..8f026f2 100644 --- a/native_client_sdk/src/libraries/nacl_io/fifo_char.h +++ b/native_client_sdk/src/libraries/nacl_io/fifo_char.h @@ -34,11 +34,11 @@ class FIFOChar : public FIFOInterface { // Reads out the data making room in the FIFO. Returns actual amount // read. - size_t Read(void* buf, size_t len); + virtual size_t Read(void* buf, size_t len); // Writes into the FIFO no more than len bytes, returns actual amount // written. - size_t Write(const void* buf, size_t len); + virtual size_t Write(const void* buf, size_t len); private: char* buffer_; diff --git a/native_client_sdk/src/libraries/nacl_io/fifo_interface.h b/native_client_sdk/src/libraries/nacl_io/fifo_interface.h index 38f53d1..d4964076 100644 --- a/native_client_sdk/src/libraries/nacl_io/fifo_interface.h +++ b/native_client_sdk/src/libraries/nacl_io/fifo_interface.h @@ -25,6 +25,8 @@ class FIFOInterface { virtual size_t ReadAvailable() = 0; virtual size_t WriteAvailable() = 0; + virtual size_t Read(void* buf, size_t len) = 0; + virtual size_t Write(const void* buf, size_t len) = 0; }; } // namespace nacl_io diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc index a141923..9ea09ff 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc @@ -1824,7 +1824,8 @@ int KernelProxy::socketpair(int domain, int type, int protocol, int* sv) { return -1; } - if (SOCK_STREAM != type) { + // TODO(cernekee): mask this off with SOCK_TYPE_MASK first. + if (SOCK_STREAM != type && SOCK_DGRAM != type) { errno = EPROTOTYPE; return -1; } @@ -1850,7 +1851,7 @@ int KernelProxy::socketpair(int domain, int type, int protocol, int* sv) { } #endif - UnixNode* socket = new UnixNode(stream_fs_.get()); + UnixNode* socket = new UnixNode(stream_fs_.get(), type); Error rtn = socket->Init(O_RDWR); if (rtn != 0) { errno = rtn; diff --git a/native_client_sdk/src/libraries/nacl_io/socket/fifo_packet.cc b/native_client_sdk/src/libraries/nacl_io/socket/fifo_packet.cc index 3e5c330..cf4a651 100644 --- a/native_client_sdk/src/libraries/nacl_io/socket/fifo_packet.cc +++ b/native_client_sdk/src/libraries/nacl_io/socket/fifo_packet.cc @@ -68,4 +68,28 @@ void FIFOPacket::WritePacket(Packet* packet) { packets_.push_front(packet); } +size_t FIFOPacket::Read(void* buf, size_t len) { + Packet* packet = ReadPacket(); + if (!packet) + return 0; + + size_t bytes = packet->len(); + if (bytes > len) + bytes = len; + memcpy(buf, packet->buffer(), bytes); + + delete packet; + return bytes; +} + +size_t FIFOPacket::Write(const void* buf, size_t len) { + if (len > WriteAvailable()) + return 0; + + Packet* packet = new Packet(NULL); + packet->Copy(buf, len, 0); + WritePacket(packet); + return len; +} + } // namespace nacl_io diff --git a/native_client_sdk/src/libraries/nacl_io/socket/fifo_packet.h b/native_client_sdk/src/libraries/nacl_io/socket/fifo_packet.h index e8ba0b3..30a25a9 100644 --- a/native_client_sdk/src/libraries/nacl_io/socket/fifo_packet.h +++ b/native_client_sdk/src/libraries/nacl_io/socket/fifo_packet.h @@ -5,6 +5,7 @@ #ifndef LIBRARIES_NACL_IO_FIFO_PACKET_H_ #define LIBRARIES_NACL_IO_FIFO_PACKET_H_ +#include <stdint.h> #include <string.h> #include <list> @@ -45,6 +46,12 @@ class FIFOPacket : public FIFOInterface { // Take ownership of packet and place it in the FIFO. void WritePacket(Packet* packet); + // Read out the top packet into a byte buffer. + size_t Read(void* buf, size_t len); + + // Enqueue a new packet from a byte buffer. + size_t Write(const void* buf, size_t len); + private: std::list<Packet*> packets_; uint32_t max_bytes_; diff --git a/native_client_sdk/src/libraries/nacl_io/socket/unix_event_emitter.cc b/native_client_sdk/src/libraries/nacl_io/socket/unix_event_emitter.cc index 1c3a523..b0a7bf3 100644 --- a/native_client_sdk/src/libraries/nacl_io/socket/unix_event_emitter.cc +++ b/native_client_sdk/src/libraries/nacl_io/socket/unix_event_emitter.cc @@ -5,8 +5,10 @@ #include "nacl_io/socket/unix_event_emitter.h" #include <stdlib.h> +#include <sys/socket.h> #include "nacl_io/fifo_char.h" +#include "nacl_io/socket/fifo_packet.h" #include "sdk_util/scoped_ref.h" namespace nacl_io { @@ -19,24 +21,33 @@ typedef sdk_util::ScopedRef<UnixMasterEventEmitter> class UnixMasterEventEmitter : public UnixEventEmitter { public: - explicit UnixMasterEventEmitter(size_t size) - : in_fifo_(size), - out_fifo_(size), - child_emitter_created_(false), - child_emitter_(NULL) { + explicit UnixMasterEventEmitter(size_t size, int type) + : child_emitter_created_(false), child_emitter_(NULL) { + if (type == SOCK_STREAM) { + in_fifo_ = new FIFOChar(size); + out_fifo_ = new FIFOChar(size); + } else { + in_fifo_ = new FIFOPacket(size); + out_fifo_ = new FIFOPacket(size); + } UpdateStatus_Locked(); } + ~UnixMasterEventEmitter() { + delete in_fifo_; + delete out_fifo_; + } + virtual ScopedUnixEventEmitter GetPeerEmitter(); protected: - virtual FIFOChar* in_fifoc() { return &in_fifo_; } - virtual FIFOChar* out_fifoc() { return &out_fifo_; } + virtual FIFOInterface* in_fifo() { return in_fifo_; } + virtual FIFOInterface* out_fifo() { return out_fifo_; } virtual const sdk_util::SimpleLock& GetFifoLock() { return fifo_lock_; } private: - FIFOChar in_fifo_; - FIFOChar out_fifo_; + FIFOInterface* in_fifo_; + FIFOInterface* out_fifo_; sdk_util::SimpleLock fifo_lock_; bool child_emitter_created_; UnixChildEventEmitter* child_emitter_; @@ -55,8 +66,8 @@ class UnixChildEventEmitter : public UnixEventEmitter { protected: virtual void Destroy() { parent_emitter_->child_emitter_ = NULL; } - virtual FIFOChar* in_fifoc() { return parent_emitter_->out_fifoc(); } - virtual FIFOChar* out_fifoc() { return parent_emitter_->in_fifoc(); } + virtual FIFOInterface* in_fifo() { return parent_emitter_->out_fifo(); } + virtual FIFOInterface* out_fifo() { return parent_emitter_->in_fifo(); } virtual const sdk_util::SimpleLock& GetFifoLock() { return parent_emitter_->GetFifoLock(); } @@ -75,7 +86,7 @@ ScopedUnixEventEmitter UnixMasterEventEmitter::GetPeerEmitter() { uint32_t UnixEventEmitter::ReadIn_Locked(char* data, uint32_t len) { AUTO_LOCK(GetFifoLock()); - uint32_t count = in_fifoc()->Read(data, len); + uint32_t count = in_fifo()->Read(data, len); ScopedUnixEventEmitter peer = GetPeerEmitter(); if (peer) { peer->UpdateStatus_Locked(); @@ -86,7 +97,7 @@ uint32_t UnixEventEmitter::ReadIn_Locked(char* data, uint32_t len) { uint32_t UnixEventEmitter::WriteOut_Locked(const char* data, uint32_t len) { AUTO_LOCK(GetFifoLock()); - uint32_t count = out_fifoc()->Write(data, len); + uint32_t count = out_fifo()->Write(data, len); ScopedUnixEventEmitter peer = GetPeerEmitter(); if (peer) { peer->UpdateStatus_Locked(); @@ -95,8 +106,9 @@ uint32_t UnixEventEmitter::WriteOut_Locked(const char* data, uint32_t len) { return count; } -ScopedUnixEventEmitter UnixEventEmitter::MakeUnixEventEmitter(size_t size) { - return ScopedUnixEventEmitter(new UnixMasterEventEmitter(size)); +ScopedUnixEventEmitter UnixEventEmitter::MakeUnixEventEmitter(size_t size, + int type) { + return ScopedUnixEventEmitter(new UnixMasterEventEmitter(size, type)); } } // namespace nacl_io diff --git a/native_client_sdk/src/libraries/nacl_io/socket/unix_event_emitter.h b/native_client_sdk/src/libraries/nacl_io/socket/unix_event_emitter.h index f8c952d..f1dba0d 100644 --- a/native_client_sdk/src/libraries/nacl_io/socket/unix_event_emitter.h +++ b/native_client_sdk/src/libraries/nacl_io/socket/unix_event_emitter.h @@ -5,7 +5,7 @@ #ifndef LIBRARIES_NACL_IO_SOCKET_UNIX_EVENT_EMITTER_H_ #define LIBRARIES_NACL_IO_SOCKET_UNIX_EVENT_EMITTER_H_ -#include "nacl_io/fifo_char.h" +#include "nacl_io/fifo_interface.h" #include "nacl_io/stream/stream_event_emitter.h" #include "sdk_util/macros.h" @@ -29,17 +29,15 @@ class UnixEventEmitter : public StreamEventEmitter { virtual ScopedUnixEventEmitter GetPeerEmitter() = 0; - static ScopedUnixEventEmitter MakeUnixEventEmitter(size_t size); + static ScopedUnixEventEmitter MakeUnixEventEmitter(size_t size, int type); protected: UnixEventEmitter() {} // Probably only need the master's lock. virtual const sdk_util::SimpleLock& GetFifoLock() = 0; - virtual FIFOInterface* in_fifo() { return in_fifoc(); } - virtual FIFOInterface* out_fifo() { return out_fifoc(); } - virtual FIFOChar* in_fifoc() = 0; - virtual FIFOChar* out_fifoc() = 0; + virtual FIFOInterface* in_fifo() = 0; + virtual FIFOInterface* out_fifo() = 0; private: DISALLOW_COPY_AND_ASSIGN(UnixEventEmitter); diff --git a/native_client_sdk/src/libraries/nacl_io/socket/unix_node.cc b/native_client_sdk/src/libraries/nacl_io/socket/unix_node.cc index 8fa44fd..968cdd7 100644 --- a/native_client_sdk/src/libraries/nacl_io/socket/unix_node.cc +++ b/native_client_sdk/src/libraries/nacl_io/socket/unix_node.cc @@ -14,9 +14,9 @@ namespace nacl_io { -UnixNode::UnixNode(Filesystem* filesystem) +UnixNode::UnixNode(Filesystem* filesystem, int type) : SocketNode(SOCK_STREAM, filesystem), - emitter_(UnixEventEmitter::MakeUnixEventEmitter(65536)) { + emitter_(UnixEventEmitter::MakeUnixEventEmitter(65536, type)) { emitter_->AttachStream(this); } diff --git a/native_client_sdk/src/libraries/nacl_io/socket/unix_node.h b/native_client_sdk/src/libraries/nacl_io/socket/unix_node.h index c8b7f30..881261a 100644 --- a/native_client_sdk/src/libraries/nacl_io/socket/unix_node.h +++ b/native_client_sdk/src/libraries/nacl_io/socket/unix_node.h @@ -16,7 +16,7 @@ namespace nacl_io { class UnixNode : public SocketNode { public: - explicit UnixNode(Filesystem* filesystem); + UnixNode(Filesystem* filesystem, int type); UnixNode(Filesystem* filesystem, const UnixNode& peer); virtual EventEmitter* GetEventEmitter(); diff --git a/native_client_sdk/src/tests/nacl_io_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_test/socket_test.cc index e2d86d5..e739f74 100644 --- a/native_client_sdk/src/tests/nacl_io_test/socket_test.cc +++ b/native_client_sdk/src/tests/nacl_io_test/socket_test.cc @@ -256,7 +256,7 @@ TEST_F(SocketTest, SocketpairUnsupported) { EXPECT_EQ(errno, EOPNOTSUPP); EXPECT_LT(ki_socketpair(AF_INET6, SOCK_STREAM, 0, sv), 0); EXPECT_EQ(errno, EOPNOTSUPP); - EXPECT_LT(ki_socketpair(AF_UNIX, SOCK_DGRAM, 0, sv), 0); + EXPECT_LT(ki_socketpair(AF_UNIX, SOCK_RAW, 0, sv), 0); EXPECT_EQ(errno, EPROTOTYPE); EXPECT_LT(ki_socketpair(AF_MAX, SOCK_STREAM, 0, sv), 0); EXPECT_EQ(errno, EAFNOSUPPORT); @@ -296,9 +296,15 @@ TEST_F(UnixSocketTest, Socketpair) { EXPECT_EQ(0, errno); EXPECT_LE(0, sv_[0]); EXPECT_LE(0, sv_[1]); + + errno = 0; + EXPECT_EQ(0, ki_socketpair(AF_UNIX, SOCK_DGRAM, 0, sv_)); + EXPECT_EQ(0, errno); + EXPECT_LE(0, sv_[0]); + EXPECT_LE(0, sv_[1]); } -TEST_F(UnixSocketTest, SendRecv) { +TEST_F(UnixSocketTest, SendRecvStream) { char outbuf[256]; char inbuf[512]; @@ -318,7 +324,7 @@ TEST_F(UnixSocketTest, SendRecv) { EXPECT_EQ(0, memcmp(outbuf, inbuf, sizeof(outbuf))); - // A reader should block after to read at this point. + // A reader should block after trying to read at this point. EXPECT_EQ(-1, ki_recv(sv_[1], inbuf, sizeof(inbuf), MSG_DONTWAIT)); EXPECT_EQ(EAGAIN, errno); @@ -338,7 +344,7 @@ TEST_F(UnixSocketTest, SendRecv) { EXPECT_EQ(EAGAIN, errno); } -TEST_F(UnixSocketTest, RecvNonBlocking) { +TEST_F(UnixSocketTest, RecvNonBlockingStream) { char buf[128]; EXPECT_EQ(0, ki_socketpair(AF_UNIX, SOCK_STREAM, 0, sv_)); @@ -352,6 +358,70 @@ TEST_F(UnixSocketTest, RecvNonBlocking) { EXPECT_NE(POLLIN, pollfd.revents & POLLIN); } +TEST_F(UnixSocketTest, SendRecvDgram) { + char outbuf1[256]; + char outbuf2[128]; + char inbuf[512]; + + memset(outbuf1, 0xA4, sizeof(outbuf1)); + memset(outbuf2, 0xA5, sizeof(outbuf2)); + memset(inbuf, 0x3C, sizeof(inbuf)); + + EXPECT_EQ(0, ki_socketpair(AF_UNIX, SOCK_DGRAM, 0, sv_)); + + int len1 = ki_send(sv_[0], outbuf1, sizeof(outbuf1), /* flags */ 0); + EXPECT_EQ(sizeof(outbuf1), len1); + + // The buffers should be different. + EXPECT_NE(0, memcmp(outbuf1, inbuf, sizeof(outbuf1))); + + int len2 = ki_send(sv_[0], outbuf2, sizeof(outbuf2), /* flags */ 0); + EXPECT_EQ(sizeof(outbuf2), len2); + + // Make sure the datagram boundaries are respected. + len1 = ki_recv(sv_[1], inbuf, sizeof(inbuf), /* flags */ 0); + EXPECT_EQ(sizeof(outbuf1), len1); + EXPECT_EQ(0, memcmp(outbuf1, inbuf, sizeof(outbuf1))); + + len2 = ki_recv(sv_[1], inbuf, sizeof(inbuf), /* flags */ 0); + EXPECT_EQ(sizeof(outbuf2), len2); + EXPECT_EQ(0, memcmp(outbuf2, inbuf, sizeof(outbuf2))); + + // A reader should block after trying to read at this point. + EXPECT_EQ(-1, ki_recv(sv_[1], inbuf, sizeof(inbuf), MSG_DONTWAIT)); + EXPECT_EQ(EAGAIN, errno); + + // Send a datagram larger than the recv buffer, and check for overflow. + memset(inbuf, 0x3C, sizeof(inbuf)); + EXPECT_NE(0, memcmp(outbuf1, inbuf, sizeof(outbuf1))); + len1 = ki_send(sv_[1], outbuf1, sizeof(outbuf1), /* flags */ 0); + EXPECT_EQ(sizeof(outbuf1), len1); + + len2 = ki_recv(sv_[0], inbuf, 16, /* flags */ 0); + EXPECT_EQ(16, len2); + EXPECT_EQ(0, memcmp(outbuf1, inbuf, 16)); + EXPECT_EQ(0x3C, inbuf[16]); + + // Verify that the remainder of the packet was discarded, and there + // is nothing left to receive. + EXPECT_EQ(-1, ki_recv(sv_[0], inbuf, sizeof(inbuf), MSG_DONTWAIT)); + EXPECT_EQ(EAGAIN, errno); +} + +TEST_F(UnixSocketTest, RecvNonBlockingDgram) { + char buf[128]; + + EXPECT_EQ(0, ki_socketpair(AF_UNIX, SOCK_DGRAM, 0, sv_)); + + EXPECT_EQ(-1, ki_recv(sv_[0], buf, sizeof(buf), MSG_DONTWAIT)); + EXPECT_EQ(EAGAIN, errno); + + struct pollfd pollfd = {sv_[0], POLLIN | POLLOUT, 0}; + EXPECT_EQ(1, ki_poll(&pollfd, 1, 0)); + EXPECT_EQ(POLLOUT, pollfd.revents & POLLOUT); + EXPECT_NE(POLLIN, pollfd.revents & POLLIN); +} + TEST(SocketUtilityFunctions, Htonl) { uint32_t host_long = 0x44332211; uint32_t network_long = htonl(host_long); |