| 1182 | } |
| 1183 | |
| 1184 | func (e *userspaceEngine) Close() { |
| 1185 | e.eventClient.Close() |
| 1186 | // TODO(cmol): Should we wait for it too? |
| 1187 | // Same question raised in appconnector.go. |
| 1188 | e.linkChangeQueue.Shutdown() |
| 1189 | e.mu.Lock() |
| 1190 | if e.closing { |
| 1191 | e.mu.Unlock() |
| 1192 | return |
| 1193 | } |
| 1194 | e.closing = true |
| 1195 | e.mu.Unlock() |
| 1196 | |
| 1197 | e.magicConn.Close() |
| 1198 | if e.netMonOwned { |
| 1199 | e.netMon.Close() |
| 1200 | } |
| 1201 | e.dns.Down() |
| 1202 | e.router.Close() |
| 1203 | e.wgdev.Close() |
| 1204 | e.tundev.Close() |
| 1205 | if e.birdClient != nil { |
| 1206 | e.birdClient.DisableProtocol("tailscale") |
| 1207 | e.birdClient.Close() |
| 1208 | } |
| 1209 | close(e.waitCh) |
| 1210 | |
| 1211 | ctx, cancel := context.WithTimeout(context.Background(), networkLoggerUploadTimeout) |
| 1212 | defer cancel() |
| 1213 | if err := e.networkLogger.Shutdown(ctx); err != nil { |
| 1214 | e.logf("wgengine: Close: error shutting down network logger: %v", err) |
| 1215 | } |
| 1216 | } |
| 1217 | |
| 1218 | func (e *userspaceEngine) Done() <-chan struct{} { |
| 1219 | return e.waitCh |