Commit 106a2a56 authored by Kevin Lewi's avatar Kevin Lewi Committed by Facebook Github Bot 6

Adding the ability to check for whether TCP fast open succeeded on a socket

Summary: Modifies AsyncSocket to check if TFO succeeded. Also added checks to AsyncSocketTest2 to check if TFO succeeded when it should.

Reviewed By: siyengar

Differential Revision: D3540330

fbshipit-source-id: 8a4b64fdb040dea73ba264b8e3dfff4d717fd96f
parent a4657e89
......@@ -46,6 +46,18 @@ int tfo_enable(int sockfd, size_t max_queue_size) {
sockfd, SOL_TCP, TCP_FASTOPEN, &max_queue_size, sizeof(max_queue_size));
}
bool tfo_succeeded(int sockfd) {
// Call getsockopt to check if TFO was used.
struct tcp_info info;
socklen_t info_len = sizeof(info);
errno = 0;
if (getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &info, &info_len) != 0) {
// errno is set from getsockopt
return false;
}
return info.tcpi_options & TCPI_OPT_SYN_DATA;
}
#else
ssize_t tfo_sendmsg(int sockfd, const struct msghdr* msg, int flags) {
......@@ -58,6 +70,11 @@ int tfo_enable(int sockfd, size_t max_queue_size) {
return -1;
}
bool tfo_succeeded(int sockfd) {
errno = EOPNOTSUPP;
return false;
}
#endif
}
}
......@@ -37,5 +37,10 @@ ssize_t tfo_sendmsg(int sockfd, const struct msghdr* msg, int flags);
* Enable TFO on a listening socket.
*/
int tfo_enable(int sockfd, size_t max_queue_size);
/**
* Check if TFO succeeded in being used.
*/
bool tfo_succeeded(int sockfd);
}
}
......@@ -1762,6 +1762,18 @@ AsyncSocket::sendSocketMessage(int fd, struct msghdr* msg, int msg_flags) {
msg->msg_namelen = len;
totalWritten = tfoSendMsg(fd_, msg, msg_flags);
if (totalWritten >= 0) {
// Call tfo_succeeded to check if TFO was used.
tfoSucceeded_ = detail::tfo_succeeded(fd_);
if (errno != 0) {
auto errnoCopy = errno;
AsyncSocketException ex(
AsyncSocketException::INTERNAL_ERROR,
withAddr("error calling tfo_succeeded"),
errnoCopy);
return WriteResult(
WRITE_ERROR, folly::make_unique<AsyncSocketException>(ex));
}
tfoFinished_ = true;
state_ = StateEnum::ESTABLISHED;
handleInitialReadWrite();
......
......@@ -431,6 +431,14 @@ class AsyncSocket : virtual public AsyncTransportWrapper {
return tfoFinished_;
}
/**
* Returns whether or not TFO "worked", or, succeeded
* in actually being used.
*/
bool getTFOSucceeded() const {
return tfoSucceeded_;
}
// Methods controlling socket options
/**
......@@ -899,6 +907,7 @@ class AsyncSocket : virtual public AsyncTransportWrapper {
bool tfoEnabled_{false};
bool tfoAttempted_{false};
bool tfoFinished_{false};
bool tfoSucceeded_{false};
};
#ifdef _MSC_VER
#pragma vtordisp(pop)
......
......@@ -2406,6 +2406,7 @@ TEST(AsyncSocketTest, ConnectTFO) {
ASSERT_EQ(1, rcb.buffers.size());
ASSERT_EQ(sizeof(buf), rcb.buffers[0].length);
EXPECT_EQ(0, memcmp(rcb.buffers[0].buffer, buf.data(), buf.size()));
EXPECT_EQ(socket->getTFOSucceeded(), socket->getTFOFinished());
}
/**
......@@ -2473,6 +2474,7 @@ TEST(AsyncSocketTest, ConnectWriteAndCloseNowTFO) {
// Loop, although there shouldn't be anything to do.
evb.loop();
EXPECT_EQ(socket->getTFOSucceeded(), socket->getTFOFinished());
CHECK_EQ(ccb.state, STATE_SUCCEEDED);
ASSERT_TRUE(socket->isClosedBySelf());
......@@ -2500,6 +2502,7 @@ TEST(AsyncSocketTest, ConnectAndCloseTFO) {
// Make sure the connection was aborted
CHECK_EQ(ccb.state, STATE_SUCCEEDED);
EXPECT_EQ(socket->getTFOSucceeded(), socket->getTFOFinished());
ASSERT_TRUE(socket->isClosedBySelf());
ASSERT_FALSE(socket->isClosedByPeer());
......@@ -2760,6 +2763,7 @@ TEST(AsyncSocketTest, ConnectTFOWithBigData) {
t.join();
EXPECT_EQ(socket->getTFOSucceeded(), socket->getTFOFinished());
EXPECT_EQ(STATE_SUCCEEDED, write.state);
EXPECT_EQ(0, memcmp(readBuf.data(), sendBuf->data(), readBuf.size()));
EXPECT_EQ(STATE_SUCCEEDED, rcb.state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment