5
5
"fmt"
6
6
"sync"
7
7
"time"
8
+ "net"
9
+ "strconv"
8
10
9
11
"github.com/godbus/dbus/v5"
10
12
"github.com/holoplot/go-avahi"
@@ -26,6 +28,7 @@ type Publisher struct {
26
28
rdataField []byte
27
29
mu sync.Mutex
28
30
cnames []string
31
+ published bool
29
32
}
30
33
31
34
func NewPublisher () (* Publisher , error ) {
@@ -74,30 +77,65 @@ func NewPublisher() (*Publisher, error) {
74
77
func (p * Publisher ) Fqdn () string {
75
78
return p .fqdn
76
79
}
77
-
78
80
func (p * Publisher ) UpdateCNAMES (cnames []string , ttl uint32 ) error {
79
81
p .mu .Lock ()
80
82
defer p .mu .Unlock ()
81
83
84
+ // If the CNAMEs haven't changed and we've already published, do nothing
85
+ if p .published && stringSlicesEqual (p .cnames , cnames ) {
86
+ return nil
87
+ }
88
+
82
89
if err := p .avahiEntryGroup .Reset (); err != nil {
83
90
utils .Error ("[mDNS] failed to reset entry group" , err )
84
91
return err
85
92
}
86
93
87
- for _ , cname := range cnames {
88
- err := p .avahiEntryGroup .AddRecord (
89
- avahi .InterfaceUnspec ,
90
- avahi .ProtoUnspec ,
91
- uint32 (0 ),
92
- cname ,
93
- AVAHI_DNS_CLASS_IN ,
94
- AVAHI_DNS_TYPE_CNAME ,
95
- ttl ,
96
- p .rdataField ,
97
- )
98
- if err != nil {
99
- utils .Error ("[mDNS] failed to add record to entry group" , err )
100
- return err
94
+ ifaces , err := net .Interfaces ()
95
+ if err != nil {
96
+ utils .Error ("[mDNS] failed to get network interfaces" , err )
97
+ return err
98
+ }
99
+
100
+ for _ , iface := range ifaces {
101
+ if iface .Flags & net .FlagLoopback != 0 {
102
+ continue
103
+ }
104
+
105
+ portStr , _ := strconv .Atoi (utils .GetServerPort ())
106
+
107
+ for _ , cname := range cnames {
108
+ utils .Log (fmt .Sprintf ("[mDNS] Adding service for: %s on interface %s" , cname , iface .Name ))
109
+ err := p .avahiEntryGroup .AddService (
110
+ int32 (iface .Index ),
111
+ avahi .ProtoUnspec ,
112
+ 0 ,
113
+ cname ,
114
+ "_http._tcp" ,
115
+ "" ,
116
+ "" ,
117
+ uint16 (portStr ),
118
+ nil ,
119
+ )
120
+ if err != nil {
121
+ utils .Error (fmt .Sprintf ("[mDNS] failed to add service to entry group for interface %s" , iface .Name ), err )
122
+ continue
123
+ }
124
+
125
+ err = p .avahiEntryGroup .AddRecord (
126
+ int32 (iface .Index ),
127
+ avahi .ProtoUnspec ,
128
+ 0 ,
129
+ cname ,
130
+ AVAHI_DNS_CLASS_IN ,
131
+ AVAHI_DNS_TYPE_CNAME ,
132
+ ttl ,
133
+ p .rdataField ,
134
+ )
135
+ if err != nil {
136
+ utils .Error (fmt .Sprintf ("[mDNS] failed to add CNAME record to entry group for interface %s" , iface .Name ), err )
137
+ continue
138
+ }
101
139
}
102
140
}
103
141
@@ -107,54 +145,39 @@ func (p *Publisher) UpdateCNAMES(cnames []string, ttl uint32) error {
107
145
}
108
146
109
147
p .cnames = cnames
148
+ p .published = true
110
149
return nil
111
150
}
112
151
113
152
func (p * Publisher ) Close () {
114
- p .avahiServer .Close ()
115
- }
116
-
117
- var publisher * Publisher
118
- var publisherMu sync.Mutex
119
-
120
- func publishing (ctx context.Context , publisher * Publisher , ttl , interval uint32 ) error {
121
- resendDuration := time .Duration (interval ) * time .Second
122
- ticker := time .NewTicker (resendDuration )
123
- defer ticker .Stop ()
124
-
125
- publishFunc := func () error {
126
- publisherMu .Lock ()
127
- cnamesToPublish := publisher .cnames
128
- publisherMu .Unlock ()
129
-
130
- err := publisher .UpdateCNAMES (cnamesToPublish , ttl )
153
+ p .mu .Lock ()
154
+ defer p .mu .Unlock ()
155
+ if p .avahiEntryGroup != nil {
156
+ err := p .avahiEntryGroup .Reset ()
131
157
if err != nil {
132
- utils .Error ("[mDNS] failed to update CNAMEs" , err )
133
- } else {
134
- utils .Debug ("[mDNS] Successfully published CNAMEs: " + fmt .Sprint (cnamesToPublish ))
158
+ utils .Error ("[mDNS] failed to reset entry group during close" , err )
135
159
}
136
- return err
160
+ p . avahiEntryGroup = nil
137
161
}
138
-
139
- // Publish immediately
140
- if err := publishFunc (); err != nil {
141
- return err
162
+ if p .avahiServer != nil {
163
+ p .avahiServer .Close ()
164
+ }
165
+ if p .dbusConn != nil {
166
+ p .dbusConn .Close ()
142
167
}
168
+ p .published = false
169
+ }
143
170
144
- for {
145
- select {
146
- case <- ticker .C :
147
- if err := publishFunc (); err != nil {
148
- utils .Error ("[mDNS] Failed to publish CNAMEs in ticker" , err )
149
- // Continue the loop instead of returning, to keep trying
150
- continue
151
- }
152
- case <- ctx .Done ():
153
- utils .Log ("[mDNS] context is done, closing publisher" )
154
- publisher .Close ()
155
- return nil
171
+ func stringSlicesEqual (a , b []string ) bool {
172
+ if len (a ) != len (b ) {
173
+ return false
174
+ }
175
+ for i , v := range a {
176
+ if v != b [i ] {
177
+ return false
156
178
}
157
179
}
180
+ return true
158
181
}
159
182
160
183
func PublishAllMDNSFromConfig () {
@@ -171,18 +194,10 @@ func PublishAllMDNSFromConfig() {
171
194
utils .Error ("[mDNS] failed to start mDNS (*.local domains). Install Avahi to solve this issue." , err )
172
195
return
173
196
}
174
-
175
- go func () {
176
- err := publishing (context .Background (), publisher , 60 , 5 )
177
- if err != nil {
178
- utils .Error ("[mDNS] mDNS publishing loop failed" , err )
179
- }
180
- }()
181
197
}
182
198
183
199
routes := utils .GetAllHostnames (false , true )
184
200
185
- // only keep .local domains
186
201
localRoutes := []string {}
187
202
188
203
if config .NewInstall {
@@ -199,7 +214,6 @@ func PublishAllMDNSFromConfig() {
199
214
200
215
utils .Log ("[mDNS] Publishing the following routes to mDNS: " + fmt .Sprint (localRoutes ))
201
216
202
- // if empty
203
217
if len (localRoutes ) == 0 {
204
218
utils .Log ("[mDNS] No .local domains to publish" )
205
219
return
@@ -209,4 +223,59 @@ func PublishAllMDNSFromConfig() {
209
223
if err != nil {
210
224
utils .Error ("[mDNS] failed to update CNAMEs" , err )
211
225
}
212
- }
226
+ }
227
+
228
+ func RestartMDNS () {
229
+ publisherMu .Lock ()
230
+ defer publisherMu .Unlock ()
231
+
232
+ if publisher != nil {
233
+ publisher .Close ()
234
+ publisher = nil
235
+ }
236
+
237
+ PublishAllMDNSFromConfig ()
238
+ }
239
+
240
+ var publisher * Publisher
241
+ var publisherMu sync.Mutex
242
+
243
+ func publishing (ctx context.Context , publisher * Publisher , ttl , interval uint32 ) error {
244
+ resendDuration := time .Duration (interval ) * time .Second
245
+ ticker := time .NewTicker (resendDuration )
246
+ defer ticker .Stop ()
247
+
248
+ publishFunc := func () error {
249
+ publisherMu .Lock ()
250
+ cnamesToPublish := publisher .cnames
251
+ publisherMu .Unlock ()
252
+
253
+ err := publisher .UpdateCNAMES (cnamesToPublish , ttl )
254
+ if err != nil {
255
+ utils .Error ("[mDNS] failed to update CNAMEs" , err )
256
+ } else {
257
+ utils .Debug ("[mDNS] Successfully published CNAMEs: " + fmt .Sprint (cnamesToPublish ))
258
+ }
259
+ return err
260
+ }
261
+
262
+ // Publish immediately
263
+ if err := publishFunc (); err != nil {
264
+ return err
265
+ }
266
+
267
+ for {
268
+ select {
269
+ case <- ticker .C :
270
+ if err := publishFunc (); err != nil {
271
+ utils .Error ("[mDNS] Failed to publish CNAMEs in ticker" , err )
272
+ // Continue the loop instead of returning, to keep trying
273
+ continue
274
+ }
275
+ case <- ctx .Done ():
276
+ utils .Log ("[mDNS] context is done, closing publisher" )
277
+ publisher .Close ()
278
+ return nil
279
+ }
280
+ }
281
+ }
0 commit comments