Summary: AsyncSocket::handleErrMessages() should check if the error message callback is still installing before calling it, since the callback could be uninstaled on the previous loop iteration.
Reviewed By: yfeldblum
Differential Revision:
D5051001
fbshipit-source-id:
fc01932c0d36bd8f72bf1905f12211fb83d28674
}
for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
}
for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- cmsg != nullptr && cmsg->cmsg_len != 0;
+ cmsg != nullptr &&
+ cmsg->cmsg_len != 0 &&
+ errMessageCallback_ != nullptr;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
errMessageCallback_->errMessage(*cmsg);
}
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
errMessageCallback_->errMessage(*cmsg);
}
void errMessage(const cmsghdr& cmsg) noexcept override {
if (cmsg.cmsg_level == SOL_SOCKET &&
cmsg.cmsg_type == SCM_TIMESTAMPING) {
void errMessage(const cmsghdr& cmsg) noexcept override {
if (cmsg.cmsg_level == SOL_SOCKET &&
cmsg.cmsg_type == SCM_TIMESTAMPING) {
+ gotTimestamp_++;
+ checkResetCallback();
} else if (
(cmsg.cmsg_level == SOL_IP && cmsg.cmsg_type == IP_RECVERR) ||
(cmsg.cmsg_level == SOL_IPV6 && cmsg.cmsg_type == IPV6_RECVERR)) {
} else if (
(cmsg.cmsg_level == SOL_IP && cmsg.cmsg_type == IP_RECVERR) ||
(cmsg.cmsg_level == SOL_IPV6 && cmsg.cmsg_type == IPV6_RECVERR)) {
+ gotByteSeq_++;
+ checkResetCallback();
+ void checkResetCallback() noexcept {
+ if (socket_ != nullptr && resetAfter_ != -1 &&
+ gotTimestamp_ + gotByteSeq_ == resetAfter_) {
+ socket_->setErrMessageCB(nullptr);
+ }
+ }
+
+ folly::AsyncSocket* socket_{nullptr};
folly::AsyncSocketException exception_;
folly::AsyncSocketException exception_;
- bool gotTimestamp_{false};
- bool gotByteSeq_{false};
+ int gotTimestamp_{0};
+ int gotByteSeq_{0};
+ int resetAfter_{-1};
};
class TestSendMsgParamsCallback :
};
class TestSendMsgParamsCallback :
SOF_TIMESTAMPING_OPT_CMSG = (1 << 10),
SOF_TIMESTAMPING_OPT_TSONLY = (1 << 11),
};
SOF_TIMESTAMPING_OPT_CMSG = (1 << 10),
SOF_TIMESTAMPING_OPT_TSONLY = (1 << 11),
};
TEST(AsyncSocketTest, ErrMessageCallback) {
TestServer server;
TEST(AsyncSocketTest, ErrMessageCallback) {
TestServer server;
ASSERT_EQ(socket->getErrMessageCallback(),
static_cast<folly::AsyncSocket::ErrMessageCallback*>(&errMsgCB));
ASSERT_EQ(socket->getErrMessageCallback(),
static_cast<folly::AsyncSocket::ErrMessageCallback*>(&errMsgCB));
+ errMsgCB.socket_ = socket.get();
+ errMsgCB.resetAfter_ = 3;
+
// Enable timestamp notifications
ASSERT_GT(socket->getFd(), 0);
int flags = SOF_TIMESTAMPING_OPT_ID
// Enable timestamp notifications
ASSERT_GT(socket->getFd(), 0);
int flags = SOF_TIMESTAMPING_OPT_ID
// write()
std::vector<uint8_t> wbuf(128, 'a');
WriteCallback wcb;
// write()
std::vector<uint8_t> wbuf(128, 'a');
WriteCallback wcb;
- socket->write(&wcb, wbuf.data(), wbuf.size());
+ // Send two packets to get two EOM notifications
+ socket->write(&wcb, wbuf.data(), wbuf.size() / 2);
+ socket->write(&wcb, wbuf.data() + wbuf.size() / 2, wbuf.size() / 2);
// Accept the connection.
std::shared_ptr<BlockingSocket> acceptedSocket = server.accept();
// Accept the connection.
std::shared_ptr<BlockingSocket> acceptedSocket = server.accept();
// Check for the timestamp notifications.
ASSERT_EQ(errMsgCB.exception_.type_, folly::AsyncSocketException::UNKNOWN);
// Check for the timestamp notifications.
ASSERT_EQ(errMsgCB.exception_.type_, folly::AsyncSocketException::UNKNOWN);
- ASSERT_TRUE(errMsgCB.gotByteSeq_);
- ASSERT_TRUE(errMsgCB.gotTimestamp_);
+ ASSERT_GT(errMsgCB.gotByteSeq_, 0);
+ ASSERT_GT(errMsgCB.gotTimestamp_, 0);
+ ASSERT_EQ(
+ errMsgCB.gotByteSeq_ + errMsgCB.gotTimestamp_, errMsgCB.resetAfter_);