diff options
Diffstat (limited to 'native_client_sdk/src')
5 files changed, 100 insertions, 13 deletions
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc index f5c20c1..d137e07 100644 --- a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc +++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc @@ -226,6 +226,8 @@ Error MountNodeSocket::GetSockOpt(int lvl, if (lvl != SOL_SOCKET) return ENOPROTOOPT; + AUTO_LOCK(node_lock_); + int value = 0; socklen_t value_len = 0; void* value_ptr = NULL; @@ -270,6 +272,8 @@ Error MountNodeSocket::SetSockOpt(int lvl, if (lvl != SOL_SOCKET) return ENOPROTOOPT; + AUTO_LOCK(node_lock_); + switch (optname) { case SO_REUSEADDR: { // SO_REUSEADDR is effectivly always on since we can't diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc index e13809d1..1366eec11 100644 --- a/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc +++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc @@ -272,13 +272,15 @@ class TCPConnectWork : public MountStream::Work { MountNodeTCP::MountNodeTCP(Mount* mount) : MountNodeSocket(mount), - emitter_(new EventEmitterTCP(kDefaultFifoSize, kDefaultFifoSize)) { + emitter_(new EventEmitterTCP(kDefaultFifoSize, kDefaultFifoSize)), + tcp_nodelay_(false) { emitter_->AttachStream(this); } MountNodeTCP::MountNodeTCP(Mount* mount, PP_Resource socket) : MountNodeSocket(mount, socket), - emitter_(new EventEmitterTCP(kDefaultFifoSize, kDefaultFifoSize)) { + emitter_(new EventEmitterTCP(kDefaultFifoSize, kDefaultFifoSize)), + tcp_nodelay_(false) { emitter_->AttachStream(this); } @@ -320,6 +322,50 @@ void MountNodeTCP::SetError_Locked(int pp_error_num) { emitter_->SetError_Locked(); } +Error MountNodeTCP::GetSockOpt(int lvl, + int optname, + void* optval, + socklen_t* len) { + if (lvl == IPPROTO_TCP && optname == TCP_NODELAY) { + AUTO_LOCK(node_lock_); + int value = tcp_nodelay_; + socklen_t value_len = sizeof(value); + int copy_bytes = std::min(value_len, *len); + memcpy(optval, &value, copy_bytes); + *len = value_len; + return 0; + } + + return MountNodeSocket::GetSockOpt(lvl, optname, optval, len); +} + + +Error MountNodeTCP::SetNoDelay_Locked() { + if (!IsConnected()) + return 0; + + int32_t error = TCPInterface()->SetOption(socket_resource_, + PP_TCPSOCKET_OPTION_NO_DELAY, + PP_MakeBool(tcp_nodelay_ ? PP_TRUE : PP_FALSE), + PP_BlockUntilComplete()); + return PPErrorToErrno(error); +} + +Error MountNodeTCP::SetSockOpt(int lvl, + int optname, + const void* optval, + socklen_t len) { + if (lvl == IPPROTO_TCP && optname == TCP_NODELAY) { + if (len < sizeof(int)) + return EINVAL; + AUTO_LOCK(node_lock_); + tcp_nodelay_ = *static_cast<const int*>(optval) != 0; + return SetNoDelay_Locked(); + } + + return MountNodeSocket::SetSockOpt(lvl, optname, optval, len); +} + void MountNodeTCP::QueueAccept() { MountStream::Work* work = new TCPAcceptWork(mount_stream(), emitter_); mount_stream()->EnqueueWork(work); @@ -464,6 +510,10 @@ void MountNodeTCP::ConnectDone_Locked() { emitter_->ConnectDone_Locked(); + // The NODELAY option cannot be set in PPAPI before the socket + // is connected, but setsockopt() might have already set it. + SetNoDelay_Locked(); + // Begin the input pump QueueInput(); } diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h index a9b6f42..6b45bc4 100644 --- a/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h +++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h @@ -39,10 +39,18 @@ class MountNodeTCP : public MountNodeSocket { struct sockaddr* addr, socklen_t* len); virtual Error Bind(const struct sockaddr* addr, socklen_t len); - virtual Error Listen(int backlog); virtual Error Connect(const HandleAttr& attr, const struct sockaddr* addr, socklen_t len); + virtual Error GetSockOpt(int lvl, + int optname, + void* optval, + socklen_t* len); + virtual Error Listen(int backlog); + virtual Error SetSockOpt(int lvl, + int optname, + const void* optval, + socklen_t len); virtual Error Shutdown(int how); virtual void SetError_Locked(int pp_error_num); @@ -50,6 +58,7 @@ class MountNodeTCP : public MountNodeSocket { void ConnectFailed_Locked(); protected: + Error SetNoDelay_Locked(); virtual Error Recv_Locked(void* buf, size_t len, PP_Resource* out_addr, @@ -62,6 +71,7 @@ class MountNodeTCP : public MountNodeSocket { ScopedEventEmitterTCP emitter_; PP_Resource accepted_socket_; + bool tcp_nodelay_; }; diff --git a/native_client_sdk/src/libraries/nacl_io/ossocket.h b/native_client_sdk/src/libraries/nacl_io/ossocket.h index 7807bfb..f62a420 100644 --- a/native_client_sdk/src/libraries/nacl_io/ossocket.h +++ b/native_client_sdk/src/libraries/nacl_io/ossocket.h @@ -11,6 +11,7 @@ #include <arpa/inet.h> #include <netdb.h> #include <netinet/in.h> +#include <netinet/tcp.h> #include <poll.h> #include <sys/socket.h> #include <sys/select.h> diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc index 6d0f3d4..5dfe004 100644 --- a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc +++ b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc @@ -344,7 +344,7 @@ TEST_F(SocketTestWithServer, TCPConnect) { IP4ToSockAddr(LOCAL_HOST, PORT1, &addr); ASSERT_EQ(0, ki_connect(sock_, (sockaddr*) &addr, addrlen)) - << "Failed with " << errno << ": " << strerror(errno) << "\n"; + << "Failed with " << errno << ": " << strerror(errno); // Send two different messages to the echo server and verify the // response matches. @@ -376,7 +376,7 @@ TEST_F(SocketTestWithServer, TCPConnectNonBlock) { SetNonBlocking(sock_); ASSERT_EQ(-1, ki_connect(sock_, (sockaddr*) &addr, addrlen)); ASSERT_EQ(EINPROGRESS, errno) - << "expected EINPROGRESS but got: " << strerror(errno) << "\n"; + << "expected EINPROGRESS but got: " << strerror(errno); ASSERT_EQ(-1, ki_connect(sock_, (sockaddr*) &addr, addrlen)); ASSERT_EQ(EALREADY, errno); @@ -420,7 +420,29 @@ TEST_F(SocketTest, Setsockopt) { ASSERT_EQ(-1, ki_setsockopt(sock1_, SOL_SOCKET, SO_ERROR, &socket_error, len)); ASSERT_EQ(ENOPROTOOPT, errno); +} + +TEST_F(SocketTest, Sockopt_TCP_NODELAY) { + int option = 0; + socklen_t len = sizeof(option); + // Getting and setting TCP_NODELAY on UDP socket should fail + sock1_ = socket(AF_INET, SOCK_DGRAM, 0); + ASSERT_EQ(-1, ki_setsockopt(sock1_, IPPROTO_TCP, TCP_NODELAY, &option, len)); + ASSERT_EQ(ENOPROTOOPT, errno); + ASSERT_EQ(-1, ki_getsockopt(sock1_, IPPROTO_TCP, TCP_NODELAY, &option, &len)); + ASSERT_EQ(ENOPROTOOPT, errno); + // Getting and setting TCP_NODELAY on TCP socket should preserve value + sock2_ = socket(AF_INET, SOCK_STREAM, 0); + ASSERT_EQ(0, ki_getsockopt(sock2_, IPPROTO_TCP, TCP_NODELAY, &option, &len)); + ASSERT_EQ(0, option); + ASSERT_EQ(sizeof(option), len); + + option = 1; + len = sizeof(option); + ASSERT_EQ(0, ki_setsockopt(sock2_, IPPROTO_TCP, TCP_NODELAY, &option, len)) + << "Failed with " << errno << ": " << strerror(errno); + ASSERT_EQ(1, option); } TEST_F(SocketTest, Sockopt_KEEPALIVE) { @@ -512,7 +534,7 @@ TEST_F(SocketTestWithServer, LargeSend) { IP4ToSockAddr(LOCAL_HOST, PORT1, &addr); ASSERT_EQ(0, ki_connect(sock_, (sockaddr*) &addr, addrlen)) - << "Failed with " << errno << ": " << strerror(errno) << "\n"; + << "Failed with " << errno << ": " << strerror(errno); // Call send an recv until all bytes have been transfered. while (bytes_received < LARGE_SEND_BYTES) { @@ -588,7 +610,7 @@ TEST_F(SocketTestTCP, Listen) { IP4ToSockAddr(LOCAL_HOST, PORT1, &addr); addrlen = sizeof(addr); ASSERT_EQ(0, ki_connect(client_sock, (sockaddr*)&addr, addrlen)) - << "Failed with " << errno << ": " << strerror(errno) << "\n"; + << "Failed with " << errno << ": " << strerror(errno); ASSERT_EQ(greeting_len, ki_send(client_sock, client_greeting, greeting_len, 0)); @@ -598,7 +620,7 @@ TEST_F(SocketTestTCP, Listen) { addrlen = sizeof(addr) + 10; int new_socket = accept(server_sock, (sockaddr*)&addr, &addrlen); ASSERT_GT(new_socket, -1) - << "accept failed with " << errno << ": " << strerror(errno) << "\n"; + << "accept failed with " << errno << ": " << strerror(errno); // Verify addr and addrlen were set correctly ASSERT_EQ(addrlen, sizeof(sockaddr_in)); @@ -652,7 +674,7 @@ TEST_F(SocketTestTCP, ListenNonBlocking) { IP4ToSockAddr(LOCAL_HOST, PORT1, &addr); addrlen = sizeof(addr); ASSERT_EQ(0, ki_connect(client_sock, (sockaddr*)&addr, addrlen)) - << "Failed with " << errno << ": " << strerror(errno) << "\n"; + << "Failed with " << errno << ": " << strerror(errno); // Not poll again but with an infintie timeout. pollfd.fd = server_sock; @@ -662,7 +684,7 @@ TEST_F(SocketTestTCP, ListenNonBlocking) { // Now non-blocking accept should return the new socket int new_socket = accept(server_sock, (sockaddr*)&addr, &addrlen); ASSERT_NE(-1, new_socket) - << "accept failed with: " << strerror(errno) << "\n"; + << "accept failed with: " << strerror(errno); ASSERT_EQ(0, ki_close(new_socket)); // Accept calls should once again fail with EAGAIN @@ -690,7 +712,7 @@ TEST_F(SocketTestTCP, SendRecvAfterRemoteShutdown) { // connect to listening socket IP4ToSockAddr(LOCAL_HOST, PORT1, &addr); ASSERT_EQ(0, ki_connect(client_sock, (sockaddr*)&addr, addrlen)) - << "Failed with " << errno << ": " << strerror(errno) << "\n"; + << "Failed with " << errno << ": " << strerror(errno); addrlen = sizeof(addr); int new_sock = accept(server_sock, (sockaddr*)&addr, &addrlen); @@ -732,7 +754,7 @@ TEST_F(SocketTestTCP, SendRecvAfterLocalShutdown) { // connect to listening socket IP4ToSockAddr(LOCAL_HOST, PORT1, &addr); ASSERT_EQ(0, ki_connect(client_sock, (sockaddr*)&addr, addrlen)) - << "Failed with " << errno << ": " << strerror(errno) << "\n"; + << "Failed with " << errno << ": " << strerror(errno); addrlen = sizeof(addr); int new_sock = accept(server_sock, (sockaddr*)&addr, &addrlen); @@ -764,7 +786,7 @@ TEST_F(SocketTestTCP, SendBufferedDataAfterShutdown) { // connect to listening socket IP4ToSockAddr(LOCAL_HOST, PORT1, &addr); ASSERT_EQ(0, ki_connect(client_sock, (sockaddr*)&addr, addrlen)) - << "Failed with " << errno << ": " << strerror(errno) << "\n"; + << "Failed with " << errno << ": " << strerror(errno); addrlen = sizeof(addr); int new_sock = accept(server_sock, (sockaddr*)&addr, &addrlen); |