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) {
return -1;
}
+bool tfo_succeeded(int sockfd) {
+ errno = EOPNOTSUPP;
+ return false;
+}
+
#endif
}
}
* 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);
}
}
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();
return tfoFinished_;
}
+ /**
+ * Returns whether or not TFO "worked", or, succeeded
+ * in actually being used.
+ */
+ bool getTFOSucceeded() const {
+ return tfoSucceeded_;
+ }
+
// Methods controlling socket options
/**
bool tfoEnabled_{false};
bool tfoAttempted_{false};
bool tfoFinished_{false};
+ bool tfoSucceeded_{false};
};
#ifdef _MSC_VER
#pragma vtordisp(pop)
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());
}
/**
// 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());
// 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());
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);