extern "C" void SystemNative_ReadEvents(int32_t sock, NetworkChangeEvent onNetworkChange) { char buffer[4096]; iovec iov = {buffer, sizeof(buffer)}; sockaddr_nl sanl; msghdr msg = { .msg_name = reinterpret_cast<void*>(&sanl), .msg_namelen = sizeof(sockaddr_nl), .msg_iov = &iov, .msg_iovlen = 1 }; ssize_t len; while (CheckInterrupted(len = recvmsg(sock, &msg, 0))); if (len == -1) { // Probably means the socket has been closed. return; } for (nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(buffer); NLMSG_OK(hdr, UnsignedCast(len)); NLMSG_NEXT(hdr, len)) { switch (hdr->nlmsg_type) { case NLMSG_DONE: return; // End of a multi-part message; stop reading. case NLMSG_ERROR: return; case RTM_NEWADDR: onNetworkChange(sock, NetworkChangeKind::AddressAdded); break; case RTM_DELADDR: onNetworkChange(sock, NetworkChangeKind::AddressRemoved); break; case RTM_NEWLINK: onNetworkChange(sock, ReadNewLinkMessage(hdr)); break; case RTM_DELLINK: onNetworkChange(sock, NetworkChangeKind::LinkRemoved); break; default: break; } } } NetworkChangeKind ReadNewLinkMessage(nlmsghdr* hdr) { assert(hdr != nullptr); ifinfomsg* ifimsg; ifimsg = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr)); if (ifimsg->ifi_family == AF_INET) { if ((ifimsg->ifi_flags & IFF_UP) != 0) { return NetworkChangeKind::LinkAdded; } } return NetworkChangeKind::None; }
extern "C" NetworkChangeKind SystemNative_ReadSingleEvent(int32_t sock) { char buffer[4096]; iovec iov = {buffer, sizeof(buffer)}; sockaddr_nl sanl; msghdr msg = { .msg_name = reinterpret_cast<void*>(&sanl), .msg_namelen = sizeof(sockaddr_nl), .msg_iov = &iov, .msg_iovlen = 1 }; ssize_t len; while (CheckInterrupted(len = recvmsg(sock, &msg, 0))); if (len == -1) { // Probably means the socket has been closed. // If so, the managed side will ignore the return value. return NetworkChangeKind::None; } nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(buffer); // This channel should only send a single message at a time. // This means there should be no multi-part messages (NLM_F_MULTI). assert((hdr->nlmsg_flags & NLM_F_MULTI) == 0); switch (hdr->nlmsg_type) { case NLMSG_DONE: return NetworkChangeKind::None; case NLMSG_ERROR: return NetworkChangeKind::None; case RTM_NEWADDR: return NetworkChangeKind::AddressAdded; case RTM_DELADDR: return NetworkChangeKind::AddressRemoved; case RTM_NEWLINK: return ReadNewLinkMessage(hdr); case RTM_DELLINK: return NetworkChangeKind::LinkRemoved; default: return NetworkChangeKind::None; } } NetworkChangeKind ReadNewLinkMessage(nlmsghdr* hdr) { assert(hdr != nullptr); ifinfomsg* ifimsg; ifimsg = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr)); if (ifimsg->ifi_family == AF_INET) { if ((ifimsg->ifi_flags & IFF_UP) != 0) { return NetworkChangeKind::LinkAdded; } } return NetworkChangeKind::None; }
extern "C" NetworkChangeKind ReadSingleEvent(int32_t sock) { char buffer[4096]; iovec iov = { buffer, sizeof(buffer) }; sockaddr_nl sanl; msghdr msg = { reinterpret_cast<void*>(&sanl), sizeof(sockaddr_nl), &iov, 1, NULL, 0, 0}; ssize_t len = recvmsg(sock, &msg, 0); if (len == -1) { // Probably means the socket has been closed. // If so, the managed side will ignore the return value. return NetworkChangeKind::None; } nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(buffer); // This channel should only send a single message at a time. // This means there should be no multi-part messages (NLM_F_MULTI). assert ((hdr->nlmsg_flags & NLM_F_MULTI) == 0); switch (hdr->nlmsg_type) { case NLMSG_DONE: return NetworkChangeKind::None; case NLMSG_ERROR: return NetworkChangeKind::None; case RTM_NEWADDR: return NetworkChangeKind::AddressAdded; case RTM_DELADDR: return NetworkChangeKind::AddressRemoved; case RTM_NEWLINK: return ReadNewLinkMessage(hdr); case RTM_DELLINK: return NetworkChangeKind::LinkRemoved; default: return NetworkChangeKind::None; } }