@@ -58,14 +58,17 @@ type Server struct {
5858 RequestHandlers map [string ]RequestHandler
5959
6060 listenerWg sync.WaitGroup
61- mu sync.Mutex
61+ mu sync.RWMutex
6262 listeners map [net.Listener ]struct {}
6363 conns map [* gossh.ServerConn ]struct {}
6464 connWg sync.WaitGroup
6565 doneChan chan struct {}
6666}
6767
6868func (srv * Server ) ensureHostSigner () error {
69+ srv .mu .Lock ()
70+ defer srv .mu .Unlock ()
71+
6972 if len (srv .HostSigners ) == 0 {
7073 signer , err := generateSigner ()
7174 if err != nil {
@@ -79,6 +82,7 @@ func (srv *Server) ensureHostSigner() error {
7982func (srv * Server ) ensureHandlers () {
8083 srv .mu .Lock ()
8184 defer srv .mu .Unlock ()
85+
8286 if srv .RequestHandlers == nil {
8387 srv .RequestHandlers = map [string ]RequestHandler {}
8488 for k , v := range DefaultRequestHandlers {
@@ -94,6 +98,9 @@ func (srv *Server) ensureHandlers() {
9498}
9599
96100func (srv * Server ) config (ctx Context ) * gossh.ServerConfig {
101+ srv .mu .RLock ()
102+ defer srv .mu .RUnlock ()
103+
97104 var config * gossh.ServerConfig
98105 if srv .ServerConfigCallback == nil {
99106 config = & gossh.ServerConfig {}
@@ -142,6 +149,9 @@ func (srv *Server) config(ctx Context) *gossh.ServerConfig {
142149
143150// Handle sets the Handler for the server.
144151func (srv * Server ) Handle (fn Handler ) {
152+ srv .mu .Lock ()
153+ defer srv .mu .Unlock ()
154+
145155 srv .Handler = fn
146156}
147157
@@ -153,6 +163,7 @@ func (srv *Server) Handle(fn Handler) {
153163func (srv * Server ) Close () error {
154164 srv .mu .Lock ()
155165 defer srv .mu .Unlock ()
166+
156167 srv .closeDoneChanLocked ()
157168 err := srv .closeListenersLocked ()
158169 for c := range srv .conns {
@@ -313,19 +324,42 @@ func (srv *Server) ListenAndServe() error {
313324// with the same algorithm, it is overwritten. Each server config must have at
314325// least one host key.
315326func (srv * Server ) AddHostKey (key Signer ) {
327+ srv .mu .Lock ()
328+ defer srv .mu .Unlock ()
329+
316330 // these are later added via AddHostKey on ServerConfig, which performs the
317331 // check for one of every algorithm.
332+
333+ // This check is based on the AddHostKey method from the x/crypto/ssh
334+ // library. This allows us to only keep one active key for each type on a
335+ // server at once. So, if you're dynamically updating keys at runtime, this
336+ // list will not keep growing.
337+ for i , k := range srv .HostSigners {
338+ if k .PublicKey ().Type () == key .PublicKey ().Type () {
339+ srv .HostSigners [i ] = key
340+ return
341+ }
342+ }
343+
318344 srv .HostSigners = append (srv .HostSigners , key )
319345}
320346
321347// SetOption runs a functional option against the server.
322348func (srv * Server ) SetOption (option Option ) error {
349+ // NOTE: there is a potential race here for any option that doesn't call an
350+ // internal method. We can't actually lock here because if something calls
351+ // (as an example) AddHostKey, it will deadlock.
352+
353+ //srv.mu.Lock()
354+ //defer srv.mu.Unlock()
355+
323356 return option (srv )
324357}
325358
326359func (srv * Server ) getDoneChan () <- chan struct {} {
327360 srv .mu .Lock ()
328361 defer srv .mu .Unlock ()
362+
329363 return srv .getDoneChanLocked ()
330364}
331365
@@ -362,6 +396,7 @@ func (srv *Server) closeListenersLocked() error {
362396func (srv * Server ) trackListener (ln net.Listener , add bool ) {
363397 srv .mu .Lock ()
364398 defer srv .mu .Unlock ()
399+
365400 if srv .listeners == nil {
366401 srv .listeners = make (map [net.Listener ]struct {})
367402 }
@@ -382,6 +417,7 @@ func (srv *Server) trackListener(ln net.Listener, add bool) {
382417func (srv * Server ) trackConn (c * gossh.ServerConn , add bool ) {
383418 srv .mu .Lock ()
384419 defer srv .mu .Unlock ()
420+
385421 if srv .conns == nil {
386422 srv .conns = make (map [* gossh.ServerConn ]struct {})
387423 }
0 commit comments