Loading automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h +27 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <array> #include <optional> #include <set> #include <string> namespace android::netdevice { Loading Loading @@ -53,14 +54,34 @@ bool exists(std::string ifname); std::optional<bool> isUp(std::string ifname); /** * Checks, if the network interface exists and is up. * * This is a convenience function to call both exists() and isUp(). * Interface condition to wait for. */ enum class WaitCondition { /** * Interface is present (but not necessarily up). */ PRESENT, /** * Interface is up. */ PRESENT_AND_UP, /** * Interface is down or not present (disconnected) at all. */ DOWN_OR_GONE, }; /** * Listens for interface changes until anticipated condition takes place. * * \param ifname Interface to check * \return true if the interface is up, false otherwise * \param ifnames List of interfaces to watch for. * \param cnd Awaited condition. * \param allOf true if all interfaces need to satisfy the condition, false if only one satistying * interface should stop the wait. */ bool existsAndIsUp(const std::string& ifname); void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true); /** * Brings network interface up. Loading automotive/can/1.0/default/libnetdevice/libnetdevice.cpp +97 −10 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <linux/rtnetlink.h> #include <net/if.h> #include <sstream> namespace android::netdevice { void useSocketDomain(int domain) { Loading @@ -37,16 +39,6 @@ bool exists(std::string ifname) { return nametoindex(ifname) != 0; } std::optional<bool> isUp(std::string ifname) { auto ifr = ifreqs::fromName(ifname); if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt; return ifr.ifr_flags & IFF_UP; } bool existsAndIsUp(const std::string& ifname) { return exists(ifname) && isUp(ifname).value_or(false); } bool up(std::string ifname) { auto ifr = ifreqs::fromName(ifname); if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false; Loading Loading @@ -102,6 +94,101 @@ bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr) { return ifreqs::send(SIOCSIFHWADDR, ifr); } std::optional<bool> isUp(std::string ifname) { auto ifr = ifreqs::fromName(ifname); if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt; return ifr.ifr_flags & IFF_UP; } struct WaitState { bool present; bool up; bool satisfied(WaitCondition cnd) const { switch (cnd) { case WaitCondition::PRESENT: if (present) return true; break; case WaitCondition::PRESENT_AND_UP: if (present && up) return true; break; case WaitCondition::DOWN_OR_GONE: if (!present || !up) return true; break; } return false; } }; static std::string toString(WaitCondition cnd) { switch (cnd) { case WaitCondition::PRESENT: return "become present"; case WaitCondition::PRESENT_AND_UP: return "come up"; case WaitCondition::DOWN_OR_GONE: return "go down"; } } static std::string toString(const std::set<std::string>& ifnames) { std::stringstream ss; std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ",")); auto str = ss.str(); str.pop_back(); return str; } void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) { nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK); using StatesMap = std::map<std::string, WaitState>; StatesMap states = {}; for (const auto ifname : ifnames) { const auto present = exists(ifname); const auto up = present && isUp(ifname).value_or(false); states[ifname] = {present, up}; } const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) { return it.second.satisfied(cnd); }; const auto isFullySatisfied = [&states, allOf, mapConditionChecker]() { if (allOf) { return std::all_of(states.begin(), states.end(), mapConditionChecker); } else { return std::any_of(states.begin(), states.end(), mapConditionChecker); } }; if (isFullySatisfied()) return; LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to " << toString(cnd); while (true) { const auto msgBuf = sock.receive(); CHECK(msgBuf.has_value()) << "Can't read Netlink socket"; for (const auto rawMsg : *msgBuf) { const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK}); if (!msg.has_value()) continue; const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME); if (ifnames.count(ifname) == 0) continue; const bool present = (msg->header.nlmsg_type != RTM_DELLINK); const bool up = present && (msg->data.ifi_flags & IFF_UP) != 0; states[ifname] = {present, up}; if (isFullySatisfied()) { LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames) << " to " << toString(cnd); return; } } } } } // namespace android::netdevice bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]) { Loading Loading
automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h +27 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <array> #include <optional> #include <set> #include <string> namespace android::netdevice { Loading Loading @@ -53,14 +54,34 @@ bool exists(std::string ifname); std::optional<bool> isUp(std::string ifname); /** * Checks, if the network interface exists and is up. * * This is a convenience function to call both exists() and isUp(). * Interface condition to wait for. */ enum class WaitCondition { /** * Interface is present (but not necessarily up). */ PRESENT, /** * Interface is up. */ PRESENT_AND_UP, /** * Interface is down or not present (disconnected) at all. */ DOWN_OR_GONE, }; /** * Listens for interface changes until anticipated condition takes place. * * \param ifname Interface to check * \return true if the interface is up, false otherwise * \param ifnames List of interfaces to watch for. * \param cnd Awaited condition. * \param allOf true if all interfaces need to satisfy the condition, false if only one satistying * interface should stop the wait. */ bool existsAndIsUp(const std::string& ifname); void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true); /** * Brings network interface up. Loading
automotive/can/1.0/default/libnetdevice/libnetdevice.cpp +97 −10 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <linux/rtnetlink.h> #include <net/if.h> #include <sstream> namespace android::netdevice { void useSocketDomain(int domain) { Loading @@ -37,16 +39,6 @@ bool exists(std::string ifname) { return nametoindex(ifname) != 0; } std::optional<bool> isUp(std::string ifname) { auto ifr = ifreqs::fromName(ifname); if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt; return ifr.ifr_flags & IFF_UP; } bool existsAndIsUp(const std::string& ifname) { return exists(ifname) && isUp(ifname).value_or(false); } bool up(std::string ifname) { auto ifr = ifreqs::fromName(ifname); if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false; Loading Loading @@ -102,6 +94,101 @@ bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr) { return ifreqs::send(SIOCSIFHWADDR, ifr); } std::optional<bool> isUp(std::string ifname) { auto ifr = ifreqs::fromName(ifname); if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt; return ifr.ifr_flags & IFF_UP; } struct WaitState { bool present; bool up; bool satisfied(WaitCondition cnd) const { switch (cnd) { case WaitCondition::PRESENT: if (present) return true; break; case WaitCondition::PRESENT_AND_UP: if (present && up) return true; break; case WaitCondition::DOWN_OR_GONE: if (!present || !up) return true; break; } return false; } }; static std::string toString(WaitCondition cnd) { switch (cnd) { case WaitCondition::PRESENT: return "become present"; case WaitCondition::PRESENT_AND_UP: return "come up"; case WaitCondition::DOWN_OR_GONE: return "go down"; } } static std::string toString(const std::set<std::string>& ifnames) { std::stringstream ss; std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ",")); auto str = ss.str(); str.pop_back(); return str; } void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) { nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK); using StatesMap = std::map<std::string, WaitState>; StatesMap states = {}; for (const auto ifname : ifnames) { const auto present = exists(ifname); const auto up = present && isUp(ifname).value_or(false); states[ifname] = {present, up}; } const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) { return it.second.satisfied(cnd); }; const auto isFullySatisfied = [&states, allOf, mapConditionChecker]() { if (allOf) { return std::all_of(states.begin(), states.end(), mapConditionChecker); } else { return std::any_of(states.begin(), states.end(), mapConditionChecker); } }; if (isFullySatisfied()) return; LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to " << toString(cnd); while (true) { const auto msgBuf = sock.receive(); CHECK(msgBuf.has_value()) << "Can't read Netlink socket"; for (const auto rawMsg : *msgBuf) { const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK}); if (!msg.has_value()) continue; const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME); if (ifnames.count(ifname) == 0) continue; const bool present = (msg->header.nlmsg_type != RTM_DELLINK); const bool up = present && (msg->data.ifi_flags & IFF_UP) != 0; states[ifname] = {present, up}; if (isFullySatisfied()) { LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames) << " to " << toString(cnd); return; } } } } } // namespace android::netdevice bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]) { Loading