Loading automotive/can/1.0/default/libnetdevice/ifreqs.cpp +7 −2 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ static SocketParams getSocketParams(int domain) { return params; } bool send(unsigned long request, struct ifreq& ifr) { int trySend(unsigned long request, struct ifreq& ifr) { const auto sp = getSocketParams(socketDomain); base::unique_fd sock(socket(sp.domain, sp.type, sp.protocol)); if (!sock.ok()) { Loading @@ -55,7 +55,12 @@ bool send(unsigned long request, struct ifreq& ifr) { return false; } if (ioctl(sock.get(), request, &ifr) < 0) { if (ioctl(sock.get(), request, &ifr) < 0) return errno; return 0; } bool send(unsigned long request, struct ifreq& ifr) { if (trySend(request, ifr) != 0) { PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed"; return false; } Loading automotive/can/1.0/default/libnetdevice/ifreqs.h +9 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,15 @@ namespace android::netdevice::ifreqs { */ extern std::atomic_int socketDomain; /** * Tries to send ioctl interface request. * * \param request Request type (such as SIOCGIFFLAGS) * \param ifr Request data (both input and output) * \return error code of the call (0 for success) */ int trySend(unsigned long request, struct ifreq& ifr); /** * Sends ioctl interface request. * Loading automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h +14 −2 Original line number Diff line number Diff line Loading @@ -67,21 +67,33 @@ enum class WaitCondition { */ PRESENT_AND_UP, /** * Interface is up and with IPv4 address configured. */ PRESENT_AND_IPV4, /** * Interface is down or not present (disconnected) at all. */ DOWN_OR_GONE, }; enum class Quantifier { ALL_OF, ANY_OF, }; /** * Listens for interface changes until anticipated condition takes place. * * \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 * \param quant Whether all interfaces need to satisfy the condition or just one satistying * interface should stop the wait. * \return name of one interface that satisfied the condition */ void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true); std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd, Quantifier quant = Quantifier::ALL_OF); /** * Brings network interface up. Loading automotive/can/1.0/default/libnetdevice/libnetdevice.cpp +76 −29 Original line number Diff line number Diff line Loading @@ -100,23 +100,36 @@ std::optional<bool> isUp(std::string ifname) { return ifr.ifr_flags & IFF_UP; } static bool hasIpv4(std::string ifname) { auto ifr = ifreqs::fromName(ifname); switch (const auto status = ifreqs::trySend(SIOCGIFADDR, ifr)) { case 0: return true; case EADDRNOTAVAIL: case ENODEV: return false; default: PLOG(WARNING) << "Failed checking IPv4 address"; return false; } } struct WaitState { bool present; bool up; bool hasIpv4Addr; bool satisfied(WaitCondition cnd) const { switch (cnd) { case WaitCondition::PRESENT: if (present) return true; break; return present; case WaitCondition::PRESENT_AND_UP: if (present && up) return true; break; return present && up; case WaitCondition::PRESENT_AND_IPV4: return present && up && hasIpv4Addr; case WaitCondition::DOWN_OR_GONE: if (!present || !up) return true; break; return !present || !up; } return false; } }; Loading @@ -126,11 +139,22 @@ static std::string toString(WaitCondition cnd) { return "become present"; case WaitCondition::PRESENT_AND_UP: return "come up"; case WaitCondition::PRESENT_AND_IPV4: return "get IPv4 address"; case WaitCondition::DOWN_OR_GONE: return "go down"; } } static std::string toString(Quantifier quant) { switch (quant) { case Quantifier::ALL_OF: return "all of"; case Quantifier::ANY_OF: return "any of"; } } 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, ",")); Loading @@ -139,50 +163,73 @@ static std::string toString(const std::set<std::string>& ifnames) { return str; } void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) { nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK); std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd, Quantifier quant) { nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK | RTMGRP_IPV4_IFADDR); 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 hasIpv4Addr = present && hasIpv4(ifname); states[ifname] = {present, up, hasIpv4Addr}; } 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); const auto isFullySatisfied = [&states, quant, mapConditionChecker]() -> std::optional<std::string> { if (quant == Quantifier::ALL_OF) { if (!std::all_of(states.begin(), states.end(), mapConditionChecker)) return {}; return states.begin()->first; } else { // Quantifier::ANY_OF const auto it = std::find_if(states.begin(), states.end(), mapConditionChecker); if (it == states.end()) return {}; return it->first; } }; if (isFullySatisfied()) return; if (const auto iface = isFullySatisfied()) return iface; LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to " LOG(DEBUG) << "Waiting for " << toString(quant) << " " << toString(ifnames) << " to " << toString(cnd); for (const auto rawMsg : sock) { const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK}); if (!msg.has_value()) continue; if (const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK}); msg.has_value()) { // Interface added / removed const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME); if (ifnames.count(ifname) == 0) continue; auto& state = states[ifname]; state.present = (msg->header.nlmsg_type != RTM_DELLINK); state.up = state.present && (msg->data.ifi_flags & IFF_UP) != 0; if (!state.present) state.hasIpv4Addr = false; } else if (const auto msg = nl::Message<ifaddrmsg>::parse(rawMsg, {RTM_NEWADDR, RTM_DELADDR}); msg.has_value()) { // Address added / removed 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 (msg->header.nlmsg_type == RTM_NEWADDR) { states[ifname].hasIpv4Addr = true; } else { // instead of tracking which one got deleted, let's just ask states[ifname].hasIpv4Addr = hasIpv4(ifname); } } if (isFullySatisfied()) { LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames) if (const auto iface = isFullySatisfied()) { LOG(DEBUG) << "Finished waiting for " << toString(quant) << " " << toString(ifnames) << " to " << toString(cnd); return; return iface; } } LOG(FATAL) << "Can't read Netlink socket"; return {}; } } // namespace android::netdevice Loading automotive/can/1.0/default/libnl++/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -37,8 +37,10 @@ cc_library_static { "protocols/generic/Unknown.cpp", "protocols/generic/families/Mac80211hwsim.cpp", "protocols/generic/families/Nl80211.cpp", "protocols/route/Addr.cpp", "protocols/route/Link.cpp", "protocols/route/Route.cpp", "protocols/route/attributes.cpp", "protocols/route/structs.cpp", "protocols/MessageDefinition.cpp", "protocols/NetlinkProtocol.cpp", Loading Loading
automotive/can/1.0/default/libnetdevice/ifreqs.cpp +7 −2 Original line number Diff line number Diff line Loading @@ -47,7 +47,7 @@ static SocketParams getSocketParams(int domain) { return params; } bool send(unsigned long request, struct ifreq& ifr) { int trySend(unsigned long request, struct ifreq& ifr) { const auto sp = getSocketParams(socketDomain); base::unique_fd sock(socket(sp.domain, sp.type, sp.protocol)); if (!sock.ok()) { Loading @@ -55,7 +55,12 @@ bool send(unsigned long request, struct ifreq& ifr) { return false; } if (ioctl(sock.get(), request, &ifr) < 0) { if (ioctl(sock.get(), request, &ifr) < 0) return errno; return 0; } bool send(unsigned long request, struct ifreq& ifr) { if (trySend(request, ifr) != 0) { PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed"; return false; } Loading
automotive/can/1.0/default/libnetdevice/ifreqs.h +9 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,15 @@ namespace android::netdevice::ifreqs { */ extern std::atomic_int socketDomain; /** * Tries to send ioctl interface request. * * \param request Request type (such as SIOCGIFFLAGS) * \param ifr Request data (both input and output) * \return error code of the call (0 for success) */ int trySend(unsigned long request, struct ifreq& ifr); /** * Sends ioctl interface request. * Loading
automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h +14 −2 Original line number Diff line number Diff line Loading @@ -67,21 +67,33 @@ enum class WaitCondition { */ PRESENT_AND_UP, /** * Interface is up and with IPv4 address configured. */ PRESENT_AND_IPV4, /** * Interface is down or not present (disconnected) at all. */ DOWN_OR_GONE, }; enum class Quantifier { ALL_OF, ANY_OF, }; /** * Listens for interface changes until anticipated condition takes place. * * \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 * \param quant Whether all interfaces need to satisfy the condition or just one satistying * interface should stop the wait. * \return name of one interface that satisfied the condition */ void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true); std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd, Quantifier quant = Quantifier::ALL_OF); /** * Brings network interface up. Loading
automotive/can/1.0/default/libnetdevice/libnetdevice.cpp +76 −29 Original line number Diff line number Diff line Loading @@ -100,23 +100,36 @@ std::optional<bool> isUp(std::string ifname) { return ifr.ifr_flags & IFF_UP; } static bool hasIpv4(std::string ifname) { auto ifr = ifreqs::fromName(ifname); switch (const auto status = ifreqs::trySend(SIOCGIFADDR, ifr)) { case 0: return true; case EADDRNOTAVAIL: case ENODEV: return false; default: PLOG(WARNING) << "Failed checking IPv4 address"; return false; } } struct WaitState { bool present; bool up; bool hasIpv4Addr; bool satisfied(WaitCondition cnd) const { switch (cnd) { case WaitCondition::PRESENT: if (present) return true; break; return present; case WaitCondition::PRESENT_AND_UP: if (present && up) return true; break; return present && up; case WaitCondition::PRESENT_AND_IPV4: return present && up && hasIpv4Addr; case WaitCondition::DOWN_OR_GONE: if (!present || !up) return true; break; return !present || !up; } return false; } }; Loading @@ -126,11 +139,22 @@ static std::string toString(WaitCondition cnd) { return "become present"; case WaitCondition::PRESENT_AND_UP: return "come up"; case WaitCondition::PRESENT_AND_IPV4: return "get IPv4 address"; case WaitCondition::DOWN_OR_GONE: return "go down"; } } static std::string toString(Quantifier quant) { switch (quant) { case Quantifier::ALL_OF: return "all of"; case Quantifier::ANY_OF: return "any of"; } } 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, ",")); Loading @@ -139,50 +163,73 @@ static std::string toString(const std::set<std::string>& ifnames) { return str; } void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) { nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK); std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd, Quantifier quant) { nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK | RTMGRP_IPV4_IFADDR); 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 hasIpv4Addr = present && hasIpv4(ifname); states[ifname] = {present, up, hasIpv4Addr}; } 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); const auto isFullySatisfied = [&states, quant, mapConditionChecker]() -> std::optional<std::string> { if (quant == Quantifier::ALL_OF) { if (!std::all_of(states.begin(), states.end(), mapConditionChecker)) return {}; return states.begin()->first; } else { // Quantifier::ANY_OF const auto it = std::find_if(states.begin(), states.end(), mapConditionChecker); if (it == states.end()) return {}; return it->first; } }; if (isFullySatisfied()) return; if (const auto iface = isFullySatisfied()) return iface; LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to " LOG(DEBUG) << "Waiting for " << toString(quant) << " " << toString(ifnames) << " to " << toString(cnd); for (const auto rawMsg : sock) { const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK}); if (!msg.has_value()) continue; if (const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK}); msg.has_value()) { // Interface added / removed const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME); if (ifnames.count(ifname) == 0) continue; auto& state = states[ifname]; state.present = (msg->header.nlmsg_type != RTM_DELLINK); state.up = state.present && (msg->data.ifi_flags & IFF_UP) != 0; if (!state.present) state.hasIpv4Addr = false; } else if (const auto msg = nl::Message<ifaddrmsg>::parse(rawMsg, {RTM_NEWADDR, RTM_DELADDR}); msg.has_value()) { // Address added / removed 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 (msg->header.nlmsg_type == RTM_NEWADDR) { states[ifname].hasIpv4Addr = true; } else { // instead of tracking which one got deleted, let's just ask states[ifname].hasIpv4Addr = hasIpv4(ifname); } } if (isFullySatisfied()) { LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames) if (const auto iface = isFullySatisfied()) { LOG(DEBUG) << "Finished waiting for " << toString(quant) << " " << toString(ifnames) << " to " << toString(cnd); return; return iface; } } LOG(FATAL) << "Can't read Netlink socket"; return {}; } } // namespace android::netdevice Loading
automotive/can/1.0/default/libnl++/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -37,8 +37,10 @@ cc_library_static { "protocols/generic/Unknown.cpp", "protocols/generic/families/Mac80211hwsim.cpp", "protocols/generic/families/Nl80211.cpp", "protocols/route/Addr.cpp", "protocols/route/Link.cpp", "protocols/route/Route.cpp", "protocols/route/attributes.cpp", "protocols/route/structs.cpp", "protocols/MessageDefinition.cpp", "protocols/NetlinkProtocol.cpp", Loading