1From 2a0f873184068f21e1d0d2a3e0d8c26bc705bf88 Mon Sep 17 00:00:00 2001
2Message-ID: <2a0f873184068f21e1d0d2a3e0d8c26bc705bf88.1687508149.git.stefan@agner.ch>
3In-Reply-To: <e136dcdcdd93ef32ada981e89c195905eb809eea.1687508149.git.stefan@agner.ch>
4References: <e136dcdcdd93ef32ada981e89c195905eb809eea.1687508149.git.stefan@agner.ch>
5From: Nate Karstens <[email protected]>
6Date: Thu, 13 Jul 2017 09:00:00 -0500
7Subject: [PATCH] Use list for changed interfaces
8
9Uses a linked list to store the index of changed network interfaces
10instead of a bitfield. This allows for network interfaces with an
11index greater than 31 (an index of 36 was seen on Android).
12
13Upstream-Status: Submitted [[email protected]]
14
15Signed-off-by: Nate Karstens <[email protected]>
16Signed-off-by: Alex Kiernan <[email protected]>
17Change-Id: Ibeab0ec68ca0d21da8384d4362e59afd2951f138
18---
19 mDNSPosix/mDNSPosix.c | 60 +++++++++++++++++++++++++++++++------------
20 1 file changed, 44 insertions(+), 16 deletions(-)
21
22diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c
23index 02a19b4..9867881 100644
24--- a/mDNSPosix/mDNSPosix.c
25+++ b/mDNSPosix/mDNSPosix.c
26@@ -74,6 +74,14 @@ struct IfChangeRec
27 };
28 typedef struct IfChangeRec IfChangeRec;
29
30+// Used to build a list of network interface indices
31+struct NetworkInterfaceIndex
32+{
33+    int if_index;
34+    struct NetworkInterfaceIndex *Next;
35+};
36+typedef struct NetworkInterfaceIndex NetworkInterfaceIndex;
37+
38 // Note that static data is initialized to zero in (modern) C.
39 static PosixEventSource *gEventSources;             // linked list of PosixEventSource's
40 static sigset_t gEventSignalSet;                // Signals which event loop listens for
41@@ -1621,6 +1629,23 @@ mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
42     return err;
43 }
44
45+mDNSlocal void AddInterfaceIndexToList(GenLinkedList *list, int if_index)
46+{
47+    NetworkInterfaceIndex *item;
48+
49+    for (item = (NetworkInterfaceIndex*)list->Head; item != NULL; item = item->Next)
50+    {
51+        if (if_index == item->if_index) return;
52+    }
53+
54+    item = mdns_malloc(sizeof *item);
55+    if (item == NULL) return;
56+
57+    item->if_index = if_index;
58+    item->Next = NULL;
59+    AddToTail(list, item);
60+}
61+
62 #if MDNS_DEBUGMSGS
63 mDNSlocal void      PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
64 {
65@@ -1648,14 +1673,13 @@ mDNSlocal void      PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
66 }
67 #endif
68
69-mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
70+mDNSlocal void          ProcessRoutingNotification(int sd, GenLinkedList *changedInterfaces)
71 // Read through the messages on sd and if any indicate that any interface records should
72 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
73 {
74     ssize_t readCount;
75     char buff[4096];
76     struct nlmsghdr         *pNLMsg = (struct nlmsghdr*) buff;
77-    mDNSu32 result = 0;
78
79     // The structure here is more complex than it really ought to be because,
80     // unfortunately, there's no good way to size a buffer in advance large
81@@ -1691,9 +1715,9 @@ mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
82
83         // Process the NetLink message
84         if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
85-            result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
86+            AddInterfaceIndexToList(changedInterfaces, ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index);
87         else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
88-            result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
89+            AddInterfaceIndexToList(changedInterfaces, ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index);
90
91         // Advance pNLMsg to the next message in the buffer
92         if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
93@@ -1704,8 +1728,6 @@ mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
94         else
95             break;  // all done!
96     }
97-
98-    return result;
99 }
100
101 #else // USES_NETLINK
102@@ -1737,18 +1759,17 @@ mDNSlocal void      PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
103 }
104 #endif
105
106-mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
107+mDNSlocal void          ProcessRoutingNotification(int sd, GenLinkedList *changedInterfaces)
108 // Read through the messages on sd and if any indicate that any interface records should
109 // be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
110 {
111     ssize_t readCount;
112     char buff[4096];
113     struct ifa_msghdr       *pRSMsg = (struct ifa_msghdr*) buff;
114-    mDNSu32 result = 0;
115
116     readCount = read(sd, buff, sizeof buff);
117     if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
118-        return mStatus_UnsupportedErr;      // cannot decipher message
119+        return;      // cannot decipher message
120
121 #if MDNS_DEBUGMSGS
122     PrintRoutingSocketMsg(pRSMsg);
123@@ -1759,12 +1780,10 @@ mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
124         pRSMsg->ifam_type == RTM_IFINFO)
125     {
126         if (pRSMsg->ifam_type == RTM_IFINFO)
127-            result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
128+            AddInterfaceIndexToList(changedInterfaces, ((struct if_msghdr*) pRSMsg)->ifm_index);
129         else
130-            result |= 1 << pRSMsg->ifam_index;
131+            AddInterfaceIndexToList(changedInterfaces, pRSMsg->ifam_index);
132     }
133-
134-    return result;
135 }
136
137 #endif // USES_NETLINK
138@@ -1774,7 +1793,8 @@ mDNSlocal void InterfaceChangeCallback(int fd, void *context)
139 {
140     IfChangeRec     *pChgRec = (IfChangeRec*) context;
141     fd_set readFDs;
142-    mDNSu32 changedInterfaces = 0;
143+    GenLinkedList changedInterfaces;
144+    NetworkInterfaceIndex *changedInterface;
145     struct timeval zeroTimeout = { 0, 0 };
146
147     (void)fd; // Unused
148@@ -1782,17 +1802,25 @@ mDNSlocal void InterfaceChangeCallback(int fd, void *context)
149     FD_ZERO(&readFDs);
150     FD_SET(pChgRec->NotifySD, &readFDs);
151
152+    InitLinkedList(&changedInterfaces, offsetof(NetworkInterfaceIndex, Next));
153+
154     do
155     {
156-        changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
157+        ProcessRoutingNotification(pChgRec->NotifySD, &changedInterfaces);
158     }
159     while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
160
161     // Currently we rebuild the entire interface list whenever any interface change is
162     // detected. If this ever proves to be a performance issue in a multi-homed
163     // configuration, more care should be paid to changedInterfaces.
164-    if (changedInterfaces)
165+    if (changedInterfaces.Head != NULL)
166         mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
167+
168+    while ((changedInterface = (NetworkInterfaceIndex*)changedInterfaces.Head) != NULL)
169+    {
170+        RemoveFromList(&changedInterfaces, changedInterface);
171+        mdns_free(changedInterface);
172+    }
173 }
174
175 // Register with either a Routing Socket or RtNetLink to listen for interface changes.
176--
1772.41.0
178
179