package ssh

import (
	
	
	
)

// 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 ( *Client) ( string) (net.Listener, error) {
	.handleForwardsOnce.Do(.handleForwards)
	 := streamLocalChannelForwardMsg{
		,
	}
	// send message
	, ,  := .SendRequest("streamlocal-forward@openssh.com", true, Marshal(&))
	if  != nil {
		return nil, 
	}
	if ! {
		return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
	}
	 := .forwards.add(&net.UnixAddr{Name: , Net: "unix"})

	return &unixListener{, , }, nil
}

func ( *Client) ( string) (Channel, error) {
	 := streamLocalChannelOpenDirectMsg{
		socketPath: ,
	}
	, ,  := .OpenChannel("direct-streamlocal@openssh.com", Marshal(&))
	if  != nil {
		return nil, 
	}
	go DiscardRequests()
	return , 
}

type unixListener struct {
	socketPath string

	conn *Client
	in   <-chan forward
}

// Accept waits for and returns the next connection to the listener.
func ( *unixListener) () (net.Conn, error) {
	,  := <-.in
	if ! {
		return nil, io.EOF
	}
	, ,  := .newCh.Accept()
	if  != nil {
		return nil, 
	}
	go DiscardRequests()

	return &chanConn{
		Channel: ,
		laddr: &net.UnixAddr{
			Name: .socketPath,
			Net:  "unix",
		},
		raddr: &net.UnixAddr{
			Name: "@",
			Net:  "unix",
		},
	}, nil
}

// Close closes the listener.
func ( *unixListener) () error {
	// this also closes the listener.
	.conn.forwards.remove(&net.UnixAddr{Name: .socketPath, Net: "unix"})
	 := streamLocalChannelForwardMsg{
		.socketPath,
	}
	, ,  := .conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&))
	if  == nil && ! {
		 = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
	}
	return 
}

// Addr returns the listener's network address.
func ( *unixListener) () net.Addr {
	return &net.UnixAddr{
		Name: .socketPath,
		Net:  "unix",
	}
}