Implement socket receive iterator
Bug: 162032964
Test: watch logcat for ifautocf and l2repeater
Test: adb shell canhalctrl up test virtual vcan2
Change-Id: Icbae3951113391846cfcf9a6747ed565bdaa7dd7
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index b3cfbe2..4c5b309 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -165,28 +165,24 @@
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 : sock) {
+ const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
+ if (!msg.has_value()) continue;
- 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 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};
- 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;
- }
+ if (isFullySatisfied()) {
+ LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames)
+ << " to " << toString(cnd);
+ return;
}
}
+ LOG(FATAL) << "Can't read Netlink socket";
}
} // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnl++/Socket.cpp b/automotive/can/1.0/default/libnl++/Socket.cpp
index 9e96ea9..08683ca 100644
--- a/automotive/can/1.0/default/libnl++/Socket.cpp
+++ b/automotive/can/1.0/default/libnl++/Socket.cpp
@@ -68,6 +68,16 @@
return true;
}
+bool Socket::increaseReceiveBuffer(size_t maxSize) {
+ if (maxSize == 0) {
+ LOG(ERROR) << "Maximum receive size should not be zero";
+ return false;
+ }
+
+ if (mReceiveBuffer.size() < maxSize) mReceiveBuffer.resize(maxSize);
+ return true;
+}
+
std::optional<Buffer<nlmsghdr>> Socket::receive(size_t maxSize) {
return receiveFrom(maxSize).first;
}
@@ -75,11 +85,7 @@
std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> Socket::receiveFrom(size_t maxSize) {
if (mFailed) return {std::nullopt, {}};
- if (maxSize == 0) {
- LOG(ERROR) << "Maximum receive size should not be zero";
- return {std::nullopt, {}};
- }
- if (mReceiveBuffer.size() < maxSize) mReceiveBuffer.resize(maxSize);
+ if (!increaseReceiveBuffer(maxSize)) return {std::nullopt, {}};
sockaddr_nl sa = {};
socklen_t saLen = sizeof(sa);
@@ -120,19 +126,16 @@
std::optional<Buffer<nlmsghdr>> Socket::receive(const std::set<nlmsgtype_t>& msgtypes,
size_t maxSize) {
- while (!mFailed) {
- const auto msgBuf = receive(maxSize);
- if (!msgBuf.has_value()) return std::nullopt;
+ if (mFailed || !increaseReceiveBuffer(maxSize)) return std::nullopt;
- for (const auto rawMsg : *msgBuf) {
- if (msgtypes.count(rawMsg->nlmsg_type) == 0) {
- LOG(WARNING) << "Received (and ignored) unexpected Netlink message of type "
- << rawMsg->nlmsg_type;
- continue;
- }
-
- return rawMsg;
+ for (const auto rawMsg : *this) {
+ if (msgtypes.count(rawMsg->nlmsg_type) == 0) {
+ LOG(WARNING) << "Received (and ignored) unexpected Netlink message of type "
+ << rawMsg->nlmsg_type;
+ continue;
}
+
+ return rawMsg;
}
return std::nullopt;
@@ -150,4 +153,47 @@
return sa.nl_pid;
}
+Socket::receive_iterator::receive_iterator(Socket& socket, bool end)
+ : mSocket(socket), mIsEnd(end) {
+ if (!end) receive();
+}
+
+Socket::receive_iterator Socket::receive_iterator::operator++() {
+ CHECK(!mIsEnd) << "Trying to increment end iterator";
+ ++mCurrent;
+ if (mCurrent.isEnd()) receive();
+ return *this;
+}
+
+bool Socket::receive_iterator::operator==(const receive_iterator& other) const {
+ if (mIsEnd != other.mIsEnd) return false;
+ if (mIsEnd && other.mIsEnd) return true;
+ return mCurrent == other.mCurrent;
+}
+
+const Buffer<nlmsghdr>& Socket::receive_iterator::operator*() const {
+ CHECK(!mIsEnd) << "Trying to dereference end iterator";
+ return *mCurrent;
+}
+
+void Socket::receive_iterator::receive() {
+ CHECK(!mIsEnd) << "Trying to receive on end iterator";
+ CHECK(mCurrent.isEnd()) << "Trying to receive without draining previous read";
+
+ const auto buf = mSocket.receive();
+ if (buf.has_value()) {
+ mCurrent = buf->begin();
+ } else {
+ mIsEnd = true;
+ }
+}
+
+Socket::receive_iterator Socket::begin() {
+ return {*this, false};
+}
+
+Socket::receive_iterator Socket::end() {
+ return {*this, true};
+}
+
} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
index c3137c8..bf83fbc 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
@@ -94,7 +94,7 @@
class iterator {
public:
iterator() : mCurrent(nullptr, size_t(0)) {
- CHECK(!mCurrent.ok()) << "end() iterator should indicate it's beyond end";
+ CHECK(isEnd()) << "end() iterator should indicate it's beyond end";
}
iterator(const Buffer<T>& buf) : mCurrent(buf) {}
@@ -108,13 +108,15 @@
bool operator==(const iterator& other) const {
// all iterators beyond end are the same
- if (!mCurrent.ok() && !other.mCurrent.ok()) return true;
+ if (isEnd() && other.isEnd()) return true;
return uintptr_t(other.mCurrent.mData) == uintptr_t(mCurrent.mData);
}
const Buffer<T>& operator*() const { return mCurrent; }
+ bool isEnd() const { return !mCurrent.ok(); }
+
protected:
Buffer<T> mCurrent;
};
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
index 6a4e82e..c69523d 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
@@ -173,6 +173,42 @@
*/
std::optional<unsigned> getPid();
+ /**
+ * Live iterator continuously receiving messages from Netlink socket.
+ *
+ * Iteration ends when socket fails to receive a buffer.
+ *
+ * Example:
+ * ```
+ * nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
+ * for (const auto rawMsg : sock) {
+ * const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
+ * if (!msg.has_value()) continue;
+ *
+ * LOG(INFO) << msg->attributes.get<std::string>(IFLA_IFNAME)
+ * << " is " << ((msg->data.ifi_flags & IFF_UP) ? "up" : "down");
+ * }
+ * LOG(FATAL) << "Failed to read from Netlink socket";
+ * ```
+ */
+ class receive_iterator {
+ public:
+ receive_iterator(Socket& socket, bool end);
+
+ receive_iterator operator++();
+ bool operator==(const receive_iterator& other) const;
+ const Buffer<nlmsghdr>& operator*() const;
+
+ private:
+ Socket& mSocket;
+ bool mIsEnd;
+ Buffer<nlmsghdr>::iterator mCurrent;
+
+ void receive();
+ };
+ receive_iterator begin();
+ receive_iterator end();
+
private:
const int mProtocol;
base::unique_fd mFd;
@@ -181,6 +217,7 @@
bool mFailed = false;
uint32_t mSeq = 0;
+ bool increaseReceiveBuffer(size_t maxSize);
std::optional<Buffer<nlmsghdr>> receive(const std::set<nlmsgtype_t>& msgtypes, size_t maxSize);
DISALLOW_COPY_AND_ASSIGN(Socket);
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
index 159b6d6..cd2e8c6 100644
--- a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
@@ -18,7 +18,7 @@
namespace android::nl::protocols {
-NetlinkProtocol::NetlinkProtocol(int protocol, const std::string name,
+NetlinkProtocol::NetlinkProtocol(int protocol, const std::string& name,
const MessageDescriptorList&& messageDescrs)
: mProtocol(protocol), mName(name), mMessageDescrs(toMap(messageDescrs, protocol)) {}
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
index 81a0a65..c969547 100644
--- a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
@@ -46,7 +46,7 @@
protected:
typedef std::vector<std::shared_ptr<const MessageDescriptor>> MessageDescriptorList;
- NetlinkProtocol(int protocol, const std::string name,
+ NetlinkProtocol(int protocol, const std::string& name,
const MessageDescriptorList&& messageDescrs);
private:
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
index 5b6bd97..134638e 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
@@ -19,7 +19,7 @@
namespace android::nl::protocols::generic {
GenericMessageBase::GenericMessageBase(
- nlmsgtype_t msgtype, std::string msgname,
+ nlmsgtype_t msgtype, const std::string&& msgname,
const std::initializer_list<GenericCommandNameMap::value_type> commandNames,
const std::initializer_list<AttributeMap::value_type> attrTypes)
: MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::UNKNOWN}}},
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
index f0ee5b0..443f10c 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
@@ -27,7 +27,7 @@
typedef std::map<uint8_t, std::string> GenericCommandNameMap;
GenericMessageBase(
- nlmsgtype_t msgtype, std::string msgname,
+ nlmsgtype_t msgtype, const std::string&& msgname,
const std::initializer_list<GenericCommandNameMap::value_type> commandNames = {},
const std::initializer_list<AttributeMap::value_type> attrTypes = {});