| 1117 | } |
| 1118 | |
| 1119 | func (e *userspaceEngine) getStatus() (*Status, error) { |
| 1120 | // Grab derpConns before acquiring wgLock to not violate lock ordering; |
| 1121 | // the DERPs method acquires magicsock.Conn.mu. |
| 1122 | // (See comment in userspaceEngine's declaration.) |
| 1123 | derpConns := e.magicConn.DERPs() |
| 1124 | |
| 1125 | e.mu.Lock() |
| 1126 | closing := e.closing |
| 1127 | peerKeys := e.peerSequence |
| 1128 | localAddrs := slices.Clone(e.endpoints) |
| 1129 | e.mu.Unlock() |
| 1130 | |
| 1131 | if closing { |
| 1132 | return nil, ErrEngineClosing |
| 1133 | } |
| 1134 | |
| 1135 | peers := make([]ipnstate.PeerStatusLite, 0, peerKeys.Len()) |
| 1136 | for _, key := range peerKeys.All() { |
| 1137 | if status, ok := e.getPeerStatusLite(key); ok { |
| 1138 | peers = append(peers, status) |
| 1139 | } |
| 1140 | } |
| 1141 | |
| 1142 | return &Status{ |
| 1143 | AsOf: time.Now(), |
| 1144 | LocalAddrs: localAddrs, |
| 1145 | Peers: peers, |
| 1146 | DERPs: derpConns, |
| 1147 | }, nil |
| 1148 | } |
| 1149 | |
| 1150 | func (e *userspaceEngine) RequestStatus() { |
| 1151 | // This is slightly tricky. e.getStatus() can theoretically get |