summaryrefslogtreecommitdiffstats
path: root/native_client_sdk/src
diff options
context:
space:
mode:
authorsbc@chromium.org <sbc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-03 02:36:59 +0000
committersbc@chromium.org <sbc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-03 02:36:59 +0000
commit410ced305a4d81885285db33e1cede0efc099f8e (patch)
tree817e61ff2c5a89ae00811e2fdabf46e016d5d606 /native_client_sdk/src
parent7ceb24d8a681acb285d581f8aae466744eead5d9 (diff)
downloadchromium_src-410ced305a4d81885285db33e1cede0efc099f8e.zip
chromium_src-410ced305a4d81885285db33e1cede0efc099f8e.tar.gz
chromium_src-410ced305a4d81885285db33e1cede0efc099f8e.tar.bz2
[NaCl SDK] nacl_io: implement set/getsockopt for TCP_NODELAY.
BUG=320450 TEST=nacl_io_socket_test + manual testing R=binji@chromium.org, noelallen@chromium.org Review URL: https://codereview.chromium.org/99813004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238281 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk/src')
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc54
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h12
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ossocket.h1
-rw-r--r--native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc42
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);