in folly/io/async/AsyncSocket.cpp [1460:1566]
void AsyncSocket::enableByteEvents() {
if (!byteEventHelper_) {
byteEventHelper_ = std::make_unique<ByteEventHelper>();
}
if (byteEventHelper_->byteEventsEnabled ||
byteEventHelper_->maybeEx.has_value()) {
return;
}
try {
#if FOLLY_HAVE_SO_TIMESTAMPING
// make sure we have a connected IP socket that supports error queues
// (Unix sockets do not support error queues)
if (NetworkSocket() == fd_ || !good()) {
throw AsyncSocketException(
AsyncSocketException::INVALID_STATE,
withAddr("failed to enable byte events: "
"socket is not open or not in a good state"));
}
folly::SocketAddress addr = {};
try {
// explicitly fetch local address (instead of using cache)
// to ensure socket is currently healthy
addr.setFromLocalAddress(fd_);
} catch (const std::system_error&) {
throw AsyncSocketException(
AsyncSocketException::INVALID_STATE,
withAddr("failed to enable byte events: "
"socket is not open or not in a good state"));
}
const auto family = addr.getFamily();
if (family != AF_INET && family != AF_INET6) {
throw AsyncSocketException(
AsyncSocketException::NOT_SUPPORTED,
withAddr("failed to enable byte events: socket type not supported"));
}
// check if timestamping is already enabled on the socket by another source
{
uint32_t flags = 0;
socklen_t len = sizeof(flags);
const auto ret =
getSockOptVirtual(SOL_SOCKET, SO_TIMESTAMPING, &flags, &len);
int getSockOptErrno = errno;
if (0 != ret) {
throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR,
withAddr("failed to enable byte events: "
"timestamps may not be supported for this socket type "
"or socket be closed"),
getSockOptErrno);
}
if (0 != flags) {
throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR,
withAddr("failed to enable byte events: "
"timestamps may have already been enabled"),
getSockOptErrno);
}
}
// enable control messages for software and hardware timestamps
// WriteFlags will determine which messages are generated
//
// SOF_TIMESTAMPING_OPT_ID: see discussion in ByteEventHelper::processCmsg
// SOF_TIMESTAMPING_OPT_TSONLY: only get timestamps, not original packet
// SOF_TIMESTAMPING_SOFTWARE: get software timestamps if generated
// SOF_TIMESTAMPING_RAW_HARDWARE: get hardware timestamps if generated
// SOF_TIMESTAMPING_OPT_TX_SWHW: get both sw + hw timestamps if generated
const uint32_t flags =
(folly::netops::SOF_TIMESTAMPING_OPT_ID |
folly::netops::SOF_TIMESTAMPING_OPT_TSONLY |
folly::netops::SOF_TIMESTAMPING_SOFTWARE |
folly::netops::SOF_TIMESTAMPING_RAW_HARDWARE |
folly::netops::SOF_TIMESTAMPING_OPT_TX_SWHW);
socklen_t len = sizeof(flags);
const auto ret =
setSockOptVirtual(SOL_SOCKET, SO_TIMESTAMPING, &flags, len);
int setSockOptErrno = errno;
if (ret == 0) {
byteEventHelper_->byteEventsEnabled = true;
byteEventHelper_->rawBytesWrittenWhenByteEventsEnabled =
getRawBytesWritten();
for (const auto& observer : lifecycleObservers_) {
if (observer->getConfig().byteEvents) {
observer->byteEventsEnabled(this);
}
}
return;
}
// failed
throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR,
withAddr("failed to enable byte events: setsockopt failed"),
setSockOptErrno);
#endif // FOLLY_HAVE_SO_TIMESTAMPING
// unsupported by platform
throw AsyncSocketException(
AsyncSocketException::NOT_SUPPORTED,
withAddr("failed to enable byte events: platform not supported"));
} catch (const AsyncSocketException& ex) {
failByteEvents(ex);
}
}