diff --git a/client.go b/client.go index 7d31c27..1d84276 100644 --- a/client.go +++ b/client.go @@ -36,6 +36,7 @@ type Client struct { Msg chan string Name string Op bool + ready chan struct{} term *terminal.Terminal termWidth int termHeight int @@ -48,6 +49,7 @@ func NewClient(server *Server, conn *ssh.ServerConn) *Client { Conn: conn, Name: conn.User(), Msg: make(chan string, MSG_BUFFER), + ready: make(chan struct{}, 1), } } @@ -86,6 +88,7 @@ func (c *Client) Rename(name string) { func (c *Client) handleShell(channel ssh.Channel) { defer channel.Close() + c.ready <- struct{}{} go func() { for msg := range c.Msg { @@ -145,6 +148,8 @@ func (c *Client) handleShell(channel ssh.Channel) { func (c *Client) handleChannels(channels <-chan ssh.NewChannel) { prompt := fmt.Sprintf("[%s] ", c.Name) + hasShell := false + for ch := range channels { if t := ch.ChannelType(); t != "session" { ch.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) @@ -156,44 +161,37 @@ func (c *Client) handleChannels(channels <-chan ssh.NewChannel) { logger.Errorf("Could not accept channel: %v", err) continue } + defer channel.Close() c.term = terminal.NewTerminal(channel, prompt) + for req := range requests { + var width, height int + var ok bool - go func(in <-chan *ssh.Request) { - defer channel.Close() - hasShell := false - for req := range in { - var width, height int - var ok bool - - switch req.Type { - case "shell": - if c.term != nil && !hasShell { - go c.handleShell(channel) - ok = true - hasShell = true - } - case "pty-req": - width, height, ok = parsePtyRequest(req.Payload) - if ok { - err := c.Resize(width, height) - ok = err == nil - } - case "window-change": - width, height, ok = parseWinchRequest(req.Payload) - if ok { - err := c.Resize(width, height) - ok = err == nil - } + switch req.Type { + case "shell": + if c.term != nil && !hasShell { + go c.handleShell(channel) + ok = true + hasShell = true } - - if req.WantReply { - req.Reply(ok, nil) + case "pty-req": + width, height, ok = parsePtyRequest(req.Payload) + if ok { + err := c.Resize(width, height) + ok = err == nil + } + case "window-change": + width, height, ok = parseWinchRequest(req.Payload) + if ok { + err := c.Resize(width, height) + ok = err == nil } } - }(requests) - // We don't care about other channels? - return + if req.WantReply { + req.Reply(ok, nil) + } + } } } diff --git a/history.go b/history.go index c5c0c5c..698b72f 100644 --- a/history.go +++ b/history.go @@ -1,10 +1,13 @@ // TODO: Split this out into its own module, it's kinda neat. package main +import "sync" + type History struct { entries []string head int size int + lock sync.Mutex } func NewHistory(size int) *History { @@ -14,6 +17,9 @@ func NewHistory(size int) *History { } func (h *History) Add(entry string) { + h.lock.Lock() + defer h.lock.Unlock() + max := cap(h.entries) h.head = (h.head + 1) % max h.entries[h.head] = entry @@ -27,6 +33,9 @@ func (h *History) Len() int { } func (h *History) Get(num int) []string { + h.lock.Lock() + defer h.lock.Unlock() + max := cap(h.entries) if num > h.size { num = h.size diff --git a/server.go b/server.go index c7ba3b1..ff835e2 100644 --- a/server.go +++ b/server.go @@ -133,6 +133,7 @@ func (s *Server) Rename(client *Client, newName string) { return } + // TODO: Use a channel/goroutine for adding clients, rathern than locks? delete(s.clients, client.Name) oldName := client.Name client.Rename(newName) @@ -193,7 +194,10 @@ func (s *Server) Start(laddr string) error { go ssh.DiscardRequests(requests) client := NewClient(s, sshConn) - client.handleChannels(channels) + go client.handleChannels(channels) + + // FIXME: This is hacky, need to restructure the concurrency. Fairly sure this will leak channels. + <-client.ready s.Add(client) go func() {