Loading automotive/can/1.0/default/libnl++/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ cc_library_static { "protocols/MessageDefinition.cpp", "protocols/NetlinkProtocol.cpp", "protocols/all.cpp", "Attributes.cpp", "NetlinkRequest.cpp", "NetlinkSocket.cpp", "common.cpp", Loading automotive/can/1.0/default/libnl++/Attributes.cpp 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libnl++/Attributes.h> namespace android::nl { Attributes::Attributes() {} Attributes::Attributes(nlbuf<nlattr> buffer) : nlbuf<nlattr>(buffer) {} const Attributes::Index& Attributes::index() const { if (mIndex.has_value()) return *mIndex; mIndex = Index(); auto& index = *mIndex; for (auto attr : static_cast<nlbuf<nlattr>>(*this)) { index.emplace(attr->nla_type, attr); } return index; } bool Attributes::contains(nlattrtype_t attrtype) const { return index().count(attrtype) > 0; } /* Parser specializations for selected types (more to come if necessary). */ template <> Attributes Attributes::parse(nlbuf<nlattr> buf) { return buf.data<nlattr>(); } template <> std::string Attributes::parse(nlbuf<nlattr> buf) { const auto rawString = buf.data<char>().getRaw(); return std::string(rawString.ptr(), rawString.len()); } template <typename T> static T parseUnsigned(nlbuf<nlattr> buf) { return buf.data<T>().copyFirst(); } template <> uint8_t Attributes::parse(nlbuf<nlattr> buf) { return parseUnsigned<uint8_t>(buf); } template <> uint16_t Attributes::parse(nlbuf<nlattr> buf) { return parseUnsigned<uint16_t>(buf); } template <> uint32_t Attributes::parse(nlbuf<nlattr> buf) { return parseUnsigned<uint32_t>(buf); } template <> uint64_t Attributes::parse(nlbuf<nlattr> buf) { return parseUnsigned<uint64_t>(buf); } } // namespace android::nl automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h 0 → 100644 +170 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android-base/logging.h> #include <libnl++/nlbuf.h> #include <libnl++/types.h> #include <utils/Mutex.h> #include <map> namespace android::nl { /** * Netlink attribute map. * * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink * message attributes. The class doesn't own the underlying data, so the instance is valid as long * as the source buffer is allocated and unmodified. * * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but * a single instance can only be used by a single thread - the one owning the underlying buffer). */ class Attributes : private nlbuf<nlattr> { public: /** * Constructs empty attribute map. */ Attributes(); /** * Construct attribute map from underlying buffer. * * \param buffer Source buffer pointing at the first attribute. */ Attributes(nlbuf<nlattr> buffer); /** * Checks, if the map contains given attribute type (key). * * \param attrtype Attribute type (such as IFLA_IFNAME). * \return true if attribute is in the map, false otherwise. */ bool contains(nlattrtype_t attrtype) const; /** * Fetches attribute of a given type by copying it. * * While this is quite efficient for simple types, fetching nested attribute creates a new copy * of child attribute map. This may be costly if you calculate the index for child maps multiple * times. Examples below. * * BAD: * ``` * const auto flags = msg->attributes. * get<nl::Attributes>(IFLA_AF_SPEC). * get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index lazy-calculated * get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated * const auto& cacheinfo = msg->attributes. * get<nl::Attributes>(IFLA_AF_SPEC). // new instance of IFLA_AF_SPEC index * get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index calculated again * getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // AF_INET6 calculated again * ``` * * GOOD: * ``` * const auto inet6 = msg->attributes. * get<nl::Attributes>(IFLA_AF_SPEC). * get<nl::Attributes>(AF_INET6); * const auto flags = inet6.get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated * const auto& cache = inet6.getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // index reused * ``` * * If the attribute doesn't exists, default value of a given type is returned and warning * spawned into the log. To check for attribute existence, \see contains(nlattrtype_t). * * \param attrtype Attribute to fetch. * \return Attribute value. */ template <typename T> T get(nlattrtype_t attrtype) const { const auto& ind = index(); const auto it = ind.find(attrtype); if (it == ind.end()) { LOG(WARNING) << "Netlink attribute is missing: " << attrtype; return T{}; } return parse<T>(it->second); } /** * Fetches a reference to a given attribute's data. * * This method is intended for arbitrary structures not specialized with get(nlattrtype_t) * template and slightly more efficient for larger payloads due to not copying its data. * * If the attribute doesn't exists, a reference to empty value of a given type is returned and * warning spawned into the log. To check for attribute existence, \see contains(nlattrtype_t). * * \param attrtype Attribute to fetch. * \return Reference to the attribute's data. */ template <typename T> const T& getStruct(nlattrtype_t attrtype) const { const auto& ind = index(); const auto it = ind.find(attrtype); if (it == ind.end()) { LOG(WARNING) << "Netlink attribute is missing: " << attrtype; static const T empty = {}; return empty; } const auto& [ok, val] = it->second.data<T>().getFirst(); if (!ok) LOG(WARNING) << "Can't fetch structure of size " << sizeof(T); return val; } private: using Index = std::map<nlattrtype_t, nlbuf<nlattr>>; /** * Attribute index. * * Since this field is not protected by mutex, the use of \see index() dependent methods * (such as \see get(nlattrtype_t)) is not thread-safe. This is a compromise made based on the * following assumptions: * * 1. Most (or even all) use-cases involve attribute parsing in the same thread as where the * buffer was allocated. This is partly forced by a dependence of nlmsg lifecycle on the * underlying data buffer. * * 2. Index calculation and access would come with performance penalty never justified in most * or all use cases (see the previous point). Since Index is not a trivially assignable data * structure, it's not possible to use it with atomic types only and avoid mutexes. */ mutable std::optional<Index> mIndex; /** * Lazy-calculate and cache index. * * \return Attribute index. */ const Index& index() const; /** * Parse attribute data into a specific type. * * \param buf Raw attribute data. * \return Parsed data. */ template <typename T> static T parse(nlbuf<nlattr> buf); }; } // namespace android::nl automotive/can/1.0/default/libnl++/include/libnl++/nlbuf.h +9 −3 Original line number Diff line number Diff line Loading @@ -53,6 +53,11 @@ class nlbuf { static constexpr size_t hdrlen = align(sizeof(T)); public: /** * Constructs empty buffer of size 0. */ nlbuf() : mData(nullptr), mBufferEnd(nullptr) {} /** * Constructor for nlbuf. * Loading @@ -68,8 +73,8 @@ class nlbuf { std::pair<bool, const T&> getFirst() const { if (!ok()) { static const T dummy = {}; return {false, dummy}; static const T empty = {}; return {false, empty}; } return {true, *mData}; } Loading @@ -78,7 +83,8 @@ class nlbuf { * Copy the first element of the buffer. * * This is a memory-safe cast operation, useful for reading e.g. uint32_t values * from 1-byte buffer. * from 1-byte buffer. If the buffer is smaller than the copied type, the rest is * padded with default constructor output (usually zeros). */ T copyFirst() const { T val = {}; Loading automotive/can/1.0/default/libnl++/include/libnl++/nlmsg.h +6 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <libnl++/Attributes.h> #include <libnl++/nlbuf.h> namespace android::nl { Loading @@ -26,6 +27,9 @@ namespace android::nl { * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink * message contents. The class doesn't own the underlying data, so the instance is valid as long as * the source buffer is allocated and unmodified. * * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but * a single instance can only be used by a single thread - the one owning the underlying buffer). */ template <typename T> class nlmsg { Loading Loading @@ -82,12 +86,12 @@ class nlmsg { /** * Netlink message attributes. */ const nlbuf<nlattr> attributes; const Attributes attributes; const T* operator->() const { return &data; } private: nlmsg(const nlmsghdr& nlHeader, const T& dataHeader, nlbuf<nlattr> attributes) nlmsg(const nlmsghdr& nlHeader, const T& dataHeader, Attributes attributes) : header(nlHeader), data(dataHeader), attributes(attributes) {} }; Loading Loading
automotive/can/1.0/default/libnl++/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ cc_library_static { "protocols/MessageDefinition.cpp", "protocols/NetlinkProtocol.cpp", "protocols/all.cpp", "Attributes.cpp", "NetlinkRequest.cpp", "NetlinkSocket.cpp", "common.cpp", Loading
automotive/can/1.0/default/libnl++/Attributes.cpp 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libnl++/Attributes.h> namespace android::nl { Attributes::Attributes() {} Attributes::Attributes(nlbuf<nlattr> buffer) : nlbuf<nlattr>(buffer) {} const Attributes::Index& Attributes::index() const { if (mIndex.has_value()) return *mIndex; mIndex = Index(); auto& index = *mIndex; for (auto attr : static_cast<nlbuf<nlattr>>(*this)) { index.emplace(attr->nla_type, attr); } return index; } bool Attributes::contains(nlattrtype_t attrtype) const { return index().count(attrtype) > 0; } /* Parser specializations for selected types (more to come if necessary). */ template <> Attributes Attributes::parse(nlbuf<nlattr> buf) { return buf.data<nlattr>(); } template <> std::string Attributes::parse(nlbuf<nlattr> buf) { const auto rawString = buf.data<char>().getRaw(); return std::string(rawString.ptr(), rawString.len()); } template <typename T> static T parseUnsigned(nlbuf<nlattr> buf) { return buf.data<T>().copyFirst(); } template <> uint8_t Attributes::parse(nlbuf<nlattr> buf) { return parseUnsigned<uint8_t>(buf); } template <> uint16_t Attributes::parse(nlbuf<nlattr> buf) { return parseUnsigned<uint16_t>(buf); } template <> uint32_t Attributes::parse(nlbuf<nlattr> buf) { return parseUnsigned<uint32_t>(buf); } template <> uint64_t Attributes::parse(nlbuf<nlattr> buf) { return parseUnsigned<uint64_t>(buf); } } // namespace android::nl
automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h 0 → 100644 +170 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android-base/logging.h> #include <libnl++/nlbuf.h> #include <libnl++/types.h> #include <utils/Mutex.h> #include <map> namespace android::nl { /** * Netlink attribute map. * * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink * message attributes. The class doesn't own the underlying data, so the instance is valid as long * as the source buffer is allocated and unmodified. * * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but * a single instance can only be used by a single thread - the one owning the underlying buffer). */ class Attributes : private nlbuf<nlattr> { public: /** * Constructs empty attribute map. */ Attributes(); /** * Construct attribute map from underlying buffer. * * \param buffer Source buffer pointing at the first attribute. */ Attributes(nlbuf<nlattr> buffer); /** * Checks, if the map contains given attribute type (key). * * \param attrtype Attribute type (such as IFLA_IFNAME). * \return true if attribute is in the map, false otherwise. */ bool contains(nlattrtype_t attrtype) const; /** * Fetches attribute of a given type by copying it. * * While this is quite efficient for simple types, fetching nested attribute creates a new copy * of child attribute map. This may be costly if you calculate the index for child maps multiple * times. Examples below. * * BAD: * ``` * const auto flags = msg->attributes. * get<nl::Attributes>(IFLA_AF_SPEC). * get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index lazy-calculated * get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated * const auto& cacheinfo = msg->attributes. * get<nl::Attributes>(IFLA_AF_SPEC). // new instance of IFLA_AF_SPEC index * get<nl::Attributes>(AF_INET6). // IFLA_AF_SPEC index calculated again * getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // AF_INET6 calculated again * ``` * * GOOD: * ``` * const auto inet6 = msg->attributes. * get<nl::Attributes>(IFLA_AF_SPEC). * get<nl::Attributes>(AF_INET6); * const auto flags = inet6.get<uint32_t>(IFLA_INET6_FLAGS); // AF_INET6 index lazy-calculated * const auto& cache = inet6.getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO); // index reused * ``` * * If the attribute doesn't exists, default value of a given type is returned and warning * spawned into the log. To check for attribute existence, \see contains(nlattrtype_t). * * \param attrtype Attribute to fetch. * \return Attribute value. */ template <typename T> T get(nlattrtype_t attrtype) const { const auto& ind = index(); const auto it = ind.find(attrtype); if (it == ind.end()) { LOG(WARNING) << "Netlink attribute is missing: " << attrtype; return T{}; } return parse<T>(it->second); } /** * Fetches a reference to a given attribute's data. * * This method is intended for arbitrary structures not specialized with get(nlattrtype_t) * template and slightly more efficient for larger payloads due to not copying its data. * * If the attribute doesn't exists, a reference to empty value of a given type is returned and * warning spawned into the log. To check for attribute existence, \see contains(nlattrtype_t). * * \param attrtype Attribute to fetch. * \return Reference to the attribute's data. */ template <typename T> const T& getStruct(nlattrtype_t attrtype) const { const auto& ind = index(); const auto it = ind.find(attrtype); if (it == ind.end()) { LOG(WARNING) << "Netlink attribute is missing: " << attrtype; static const T empty = {}; return empty; } const auto& [ok, val] = it->second.data<T>().getFirst(); if (!ok) LOG(WARNING) << "Can't fetch structure of size " << sizeof(T); return val; } private: using Index = std::map<nlattrtype_t, nlbuf<nlattr>>; /** * Attribute index. * * Since this field is not protected by mutex, the use of \see index() dependent methods * (such as \see get(nlattrtype_t)) is not thread-safe. This is a compromise made based on the * following assumptions: * * 1. Most (or even all) use-cases involve attribute parsing in the same thread as where the * buffer was allocated. This is partly forced by a dependence of nlmsg lifecycle on the * underlying data buffer. * * 2. Index calculation and access would come with performance penalty never justified in most * or all use cases (see the previous point). Since Index is not a trivially assignable data * structure, it's not possible to use it with atomic types only and avoid mutexes. */ mutable std::optional<Index> mIndex; /** * Lazy-calculate and cache index. * * \return Attribute index. */ const Index& index() const; /** * Parse attribute data into a specific type. * * \param buf Raw attribute data. * \return Parsed data. */ template <typename T> static T parse(nlbuf<nlattr> buf); }; } // namespace android::nl
automotive/can/1.0/default/libnl++/include/libnl++/nlbuf.h +9 −3 Original line number Diff line number Diff line Loading @@ -53,6 +53,11 @@ class nlbuf { static constexpr size_t hdrlen = align(sizeof(T)); public: /** * Constructs empty buffer of size 0. */ nlbuf() : mData(nullptr), mBufferEnd(nullptr) {} /** * Constructor for nlbuf. * Loading @@ -68,8 +73,8 @@ class nlbuf { std::pair<bool, const T&> getFirst() const { if (!ok()) { static const T dummy = {}; return {false, dummy}; static const T empty = {}; return {false, empty}; } return {true, *mData}; } Loading @@ -78,7 +83,8 @@ class nlbuf { * Copy the first element of the buffer. * * This is a memory-safe cast operation, useful for reading e.g. uint32_t values * from 1-byte buffer. * from 1-byte buffer. If the buffer is smaller than the copied type, the rest is * padded with default constructor output (usually zeros). */ T copyFirst() const { T val = {}; Loading
automotive/can/1.0/default/libnl++/include/libnl++/nlmsg.h +6 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <libnl++/Attributes.h> #include <libnl++/nlbuf.h> namespace android::nl { Loading @@ -26,6 +27,9 @@ namespace android::nl { * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink * message contents. The class doesn't own the underlying data, so the instance is valid as long as * the source buffer is allocated and unmodified. * * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but * a single instance can only be used by a single thread - the one owning the underlying buffer). */ template <typename T> class nlmsg { Loading Loading @@ -82,12 +86,12 @@ class nlmsg { /** * Netlink message attributes. */ const nlbuf<nlattr> attributes; const Attributes attributes; const T* operator->() const { return &data; } private: nlmsg(const nlmsghdr& nlHeader, const T& dataHeader, nlbuf<nlattr> attributes) nlmsg(const nlmsghdr& nlHeader, const T& dataHeader, Attributes attributes) : header(nlHeader), data(dataHeader), attributes(attributes) {} }; Loading