text: package ssh
  
  import (
  	"errors"
  	"io"
  	"net"
  )
  
  // streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
  // with "direct-streamlocal@openssh.com" string.
  //
  // See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
  // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
  type streamLocalChannelOpenDirectMsg struct {
  	socketPath string
  	reserved0  string
  	reserved1  uint32
  }
  
  // forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
  // with "forwarded-streamlocal@openssh.com" string.
  type forwardedStreamLocalPayload struct {
  	SocketPath string
  	Reserved0  string
  }
  
  // streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
  // with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
  type streamLocalChannelForwardMsg struct {
  	socketPath string
  }
  
  // ListenUnix is similar to ListenTCP but uses a Unix domain socket.
  func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
  	c.handleForwardsOnce.Do(c.handleForwards)
  	m := streamLocalChannelForwardMsg{
  		socketPath,
  	}
  	// send message
  	ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m))
  	if err != nil {
  		return nil, err
  	}
  	if !ok {
  		return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
  	}
  	ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"})
  
  	return &unixListener{socketPath, c, ch}, nil
  }
  
  func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
  	msg := streamLocalChannelOpenDirectMsg{
  		socketPath: socketPath,
  	}
  	ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg))
  	if err != nil {
  		return nil, err
  	}
  	go DiscardRequests(in)
  	return ch, err
  }
  
  type unixListener struct {
  	socketPath string
  
  	conn *Client
  	in   <-chan forward
  }
  
  // Accept waits for and returns the next connection to the listener.
  func (l *unixListener) Accept() (net.Conn, error) {
  	s, ok := <-l.in
  	if !ok {
  		return nil, io.EOF
  	}
  	ch, incoming, err := s.newCh.Accept()
  	if err != nil {
  		return nil, err
  	}
  	go DiscardRequests(incoming)
  
  	return &chanConn{
  		Channel: ch,
  		laddr: &net.UnixAddr{
  			Name: l.socketPath,
  			Net:  "unix",
  		},
  		raddr: &net.UnixAddr{
  			Name: "@",
  			Net:  "unix",
  		},
  	}, nil
  }
  
  // Close closes the listener.
  func (l *unixListener) Close() error {
  	// this also closes the listener.
  	l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"})
  	m := streamLocalChannelForwardMsg{
  		l.socketPath,
  	}
  	ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m))
  	if err == nil && !ok {
  		err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
  	}
  	return err
  }
  
  // Addr returns the listener's network address.
  func (l *unixListener) Addr() net.Addr {
  	return &net.UnixAddr{
  		Name: l.socketPath,
  		Net:  "unix",
  	}
  }
  