From e79f81f5cd626ad77ec64de4325f6645cf253c5e Mon Sep 17 00:00:00 2001 From: Nate Karstens Date: Thu, 13 Jul 2017 09:00:00 -0500 Subject: [PATCH 5/8] Use list for changed interfaces Uses a linked list to store the index of changed network interfaces instead of a bitfield. This allows for network interfaces with an index greater than 31 (an index of 36 was seen on Android). Upstream-Status: Submitted [dts@apple.com] Signed-off-by: Nate Karstens Signed-off-by: Alex Kiernan --- mDNSPosix/mDNSPosix.c | 58 ++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 15 deletions(-) --- a/mDNSPosix/mDNSPosix.c +++ b/mDNSPosix/mDNSPosix.c @@ -74,6 +74,14 @@ struct IfChangeRec }; typedef struct IfChangeRec IfChangeRec; +// Used to build a list of network interface indices +struct NetworkInterfaceIndex +{ + int if_index; + struct NetworkInterfaceIndex *Next; +}; +typedef struct NetworkInterfaceIndex NetworkInterfaceIndex; + // Note that static data is initialized to zero in (modern) C. static PosixEventSource *gEventSources; // linked list of PosixEventSource's static sigset_t gEventSignalSet; // Signals which event loop listens for @@ -1621,6 +1629,23 @@ mDNSlocal mStatus OpenIfNotifySocket(int return err; } +mDNSlocal void AddInterfaceIndexToList(GenLinkedList *list, int if_index) +{ + NetworkInterfaceIndex *item; + + for (item = (NetworkInterfaceIndex*)list->Head; item != NULL; item = item->Next) + { + if (if_index == item->if_index) return; + } + + item = mdns_malloc(sizeof *item); + if (item == NULL) return; + + item->if_index = if_index; + item->Next = NULL; + AddToTail(list, item); +} + #if MDNS_DEBUGMSGS mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg) { @@ -1648,14 +1673,13 @@ mDNSlocal void PrintNetLinkMsg(cons } #endif -mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) +mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *changedInterfaces) // Read through the messages on sd and if any indicate that any interface records should // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. { ssize_t readCount; char buff[4096]; struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff; - mDNSu32 result = 0; // The structure here is more complex than it really ought to be because, // unfortunately, there's no good way to size a buffer in advance large @@ -1691,9 +1715,9 @@ mDNSlocal mDNSu32 ProcessRoutingNo // Process the NetLink message if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK) - result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index; + AddInterfaceIndexToList(changedInterfaces, ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index); else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR) - result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index; + AddInterfaceIndexToList(changedInterfaces, ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index); // Advance pNLMsg to the next message in the buffer if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE) @@ -1704,8 +1728,6 @@ mDNSlocal mDNSu32 ProcessRoutingNo else break; // all done! } - - return result; } #else // USES_NETLINK @@ -1737,14 +1759,13 @@ mDNSlocal void PrintRoutingSocketMs } #endif -mDNSlocal mDNSu32 ProcessRoutingNotification(int sd) +mDNSlocal void ProcessRoutingNotification(int sd, GenLinkedList *changedInterfaces) // Read through the messages on sd and if any indicate that any interface records should // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0. { ssize_t readCount; char buff[4096]; struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff; - mDNSu32 result = 0; readCount = read(sd, buff, sizeof buff); if (readCount < (ssize_t) sizeof(struct ifa_msghdr)) @@ -1759,12 +1780,10 @@ mDNSlocal mDNSu32 ProcessRoutingNo pRSMsg->ifam_type == RTM_IFINFO) { if (pRSMsg->ifam_type == RTM_IFINFO) - result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index; + AddInterfaceIndexToList(changedInterfaces, ((struct if_msghdr*) pRSMsg)->ifm_index); else - result |= 1 << pRSMsg->ifam_index; + AddInterfaceIndexToList(changedInterfaces, pRSMsg->ifam_index); } - - return result; } #endif // USES_NETLINK @@ -1774,7 +1793,8 @@ mDNSlocal void InterfaceChangeCallback(i { IfChangeRec *pChgRec = (IfChangeRec*) context; fd_set readFDs; - mDNSu32 changedInterfaces = 0; + GenLinkedList changedInterfaces; + NetworkInterfaceIndex *changedInterface; struct timeval zeroTimeout = { 0, 0 }; (void)fd; // Unused @@ -1782,17 +1802,25 @@ mDNSlocal void InterfaceChangeCallback(i FD_ZERO(&readFDs); FD_SET(pChgRec->NotifySD, &readFDs); + InitLinkedList(&changedInterfaces, offsetof(NetworkInterfaceIndex, Next)); + do { - changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD); + ProcessRoutingNotification(pChgRec->NotifySD, &changedInterfaces); } while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout)); // Currently we rebuild the entire interface list whenever any interface change is // detected. If this ever proves to be a performance issue in a multi-homed // configuration, more care should be paid to changedInterfaces. - if (changedInterfaces) + if (changedInterfaces.Head != NULL) mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS); + + while ((changedInterface = (NetworkInterfaceIndex*)changedInterfaces.Head) != NULL) + { + RemoveFromList(&changedInterfaces, changedInterface); + mdns_free(changedInterface); + } } // Register with either a Routing Socket or RtNetLink to listen for interface changes.