void Netlink::handle_msg()

in Netlink.cpp [380:478]


void Netlink::handle_msg(uint16_t msg_type, uint16_t msg_flags, uint32_t msg_seq, const void* payload_data, size_t payload_len) {
    reply_fn_t* fn_ptr = nullptr;
    bool done = false;

    std::shared_ptr<ReplyRec> reply;

    if (msg_seq != 0) {
        // The seq is non-zero so this message should be a reply to a request
        // look for the reply_fn associates with this seq #
        std::lock_guard<std::mutex> _lock(_run_mutex);
        auto itr = _replies.find(msg_seq);
        if (itr != _replies.end()) {
            reply = itr->second;
            fn_ptr = &reply->_fn;
            done = reply->_done;
            reply->_req_age = std::chrono::steady_clock::now();
            _known_seq[msg_seq] = reply->_req_age;
        } else {
            // No ReplyRec found for the seq #
            done = true;
            // Only print a warning if the seq # is not known
            if (_known_seq.count(msg_seq) == 0) {
                Logger::Warn("Received unexpected NETLINK packet (Type: %d, Flags: 0x%X, Seq: %d, Size: %ld",
                             msg_type, msg_flags, msg_seq, payload_len);
            }
        }
    } else {
        if (_default_msg_handler_fn) {
            fn_ptr = &_default_msg_handler_fn;
        } else {
            done = true;
            Logger::Warn(
                    "Received NETLINK packet With Seq 0 and no default handler is defined (Type: %d, Flags: 0x%X, Size: %ld",
                    msg_type, msg_flags, payload_len);
        }
    }

    // If the request hasn't been marked done, has a valid reply_fn associated, and the message is not of type NLMSG_ERRROR or NLMSG_DONE
    // then call the reply_fn
    if (!done && fn_ptr != nullptr && *fn_ptr && msg_type != NLMSG_ERROR && msg_type != NLMSG_DONE) {
        try {
            if (!(*fn_ptr)(msg_type, msg_flags, payload_data, payload_len) && msg_seq > 0) {
                // The reply_fn returned false, so mark the request as complete.
                std::lock_guard<std::mutex> _lock(_run_mutex);
                if (reply) {
                    reply->_done = true;
                    reply->_promise.set_value(0);
                }
                return;
            }
        } catch (const std::exception &ex) {
            if (msg_seq > 0) {
                // The reply_fn threw an exception, try to propagate the exception through the request promise
                std::lock_guard<std::mutex> _lock(_run_mutex);
                if (reply) {
                    try {
                        reply->_promise.set_exception(std::current_exception());
                        reply->_done = true;
                    } catch (const std::exception &ex) {
                        Logger::Error(
                                "Unexpected exception while trying to set exception in NETLINK msg reply promise: %s",
                                ex.what());
                    }
                    _replies.erase(msg_seq);
                }
            }
            return;
        }
    }

    if (msg_seq != 0) {
        if (msg_type == NLMSG_ERROR) {
            auto err = reinterpret_cast<const nlmsgerr *>(payload_data);
            std::lock_guard<std::mutex> _lock(_run_mutex);
            // If the request failed, or the request succeeded but no response is expected then set the value to err->error
            // If !fn then no response is expected and the return value is err->error (typically == 0)
            if (err->error != 0 || fn_ptr == nullptr || !(*fn_ptr)) {
                if (reply) {
                    if (!reply->_done) {
                        reply->_done = true;
                        reply->_promise.set_value(err->error);
                    }
                    _replies.erase(msg_seq);
                }
                _known_seq.erase(msg_seq);
            }
        } else if ((msg_flags & NLM_F_MULTI) == 0 || msg_type == NLMSG_DONE) {
            std::lock_guard<std::mutex> _lock(_run_mutex);
            if (reply) {
                if (!reply->_done) {
                    reply->_promise.set_value(0);
                    reply->_done = true;
                }
                _replies.erase(msg_seq);
            }
            _known_seq.erase(msg_seq);
        }
    }
}