Multi-client servers + bring back stdinserver support

This commit is contained in:
Christian Schwarz
2018-09-04 16:41:54 -07:00
parent e161347e47
commit 308e5e35fb
12 changed files with 356 additions and 71 deletions
+101 -18
View File
@@ -8,54 +8,133 @@ import (
"net"
"path"
"time"
"context"
"github.com/pkg/errors"
"sync/atomic"
"fmt"
"os"
)
type StdinserverListenerFactory struct {
ClientIdentity string
sockpath string
ClientIdentities []string
Sockdir string
}
func StdinserverListenerFactoryFromConfig(g *config.Global, in *config.StdinserverServer) (f *StdinserverListenerFactory, err error) {
func MultiStdinserverListenerFactoryFromConfig(g *config.Global, in *config.StdinserverServer) (f *multiStdinserverListenerFactory, err error) {
f = &StdinserverListenerFactory{
ClientIdentity: in.ClientIdentity,
for _, ci := range in.ClientIdentities {
if err := ValidateClientIdentity(ci); err != nil {
return nil, errors.Wrapf(err, "invalid client identity %q", ci)
}
}
f.sockpath = path.Join(g.Serve.StdinServer.SockDir, f.ClientIdentity)
f = &multiStdinserverListenerFactory{
ClientIdentities: in.ClientIdentities,
Sockdir: g.Serve.StdinServer.SockDir,
}
return
}
func (f *StdinserverListenerFactory) Listen() (net.Listener, error) {
type multiStdinserverListenerFactory struct {
ClientIdentities []string
Sockdir string
}
if err := nethelpers.PreparePrivateSockpath(f.sockpath); err != nil {
return nil, err
func (f *multiStdinserverListenerFactory) Listen() (AuthenticatedListener, error) {
return multiStdinserverListenerFromClientIdentities(f.Sockdir, f.ClientIdentities)
}
type multiStdinserverAcceptRes struct {
conn AuthenticatedConn
err error
}
type MultiStdinserverListener struct {
listeners []*stdinserverListener
accepts chan multiStdinserverAcceptRes
closed int32
}
// client identities must be validated
func multiStdinserverListenerFromClientIdentities(sockdir string, cis []string) (*MultiStdinserverListener, error) {
listeners := make([]*stdinserverListener, 0, len(cis))
var err error
for _, ci := range cis {
sockpath := path.Join(sockdir, ci)
l := &stdinserverListener{clientIdentity: ci}
if err = nethelpers.PreparePrivateSockpath(sockpath); err != nil {
break
}
if l.l, err = netssh.Listen(sockpath); err != nil {
break
}
listeners = append(listeners, l)
}
l, err := netssh.Listen(f.sockpath)
if err != nil {
for _, l := range listeners {
l.Close() // FIXME error reporting?
}
return nil, err
}
return StdinserverListener{l}, nil
return &MultiStdinserverListener{listeners: listeners}, nil
}
type StdinserverListener struct {
l *netssh.Listener
func (m *MultiStdinserverListener) Accept(ctx context.Context) (AuthenticatedConn, error){
if m.accepts == nil {
m.accepts = make(chan multiStdinserverAcceptRes, len(m.listeners))
for i := range m.listeners {
go func(i int) {
for atomic.LoadInt32(&m.closed) == 0 {
fmt.Fprintf(os.Stderr, "accepting\n")
conn, err := m.listeners[i].Accept(context.TODO())
fmt.Fprintf(os.Stderr, "incoming\n")
m.accepts <- multiStdinserverAcceptRes{conn, err}
}
}(i)
}
}
res := <- m.accepts
return res.conn, res.err
}
func (l StdinserverListener) Addr() net.Addr {
func (m *MultiStdinserverListener) Addr() (net.Addr) {
return netsshAddr{}
}
func (l StdinserverListener) Accept() (net.Conn, error) {
func (m *MultiStdinserverListener) Close() error {
atomic.StoreInt32(&m.closed, 1)
var oneErr error
for _, l := range m.listeners {
if err := l.Close(); err != nil && oneErr == nil {
oneErr = err
}
}
return oneErr
}
// a single stdinserverListener (part of multiStinserverListener)
type stdinserverListener struct {
l *netssh.Listener
clientIdentity string
}
func (l stdinserverListener) Addr() net.Addr {
return netsshAddr{}
}
func (l stdinserverListener) Accept(ctx context.Context) (AuthenticatedConn, error) {
c, err := l.l.Accept()
if err != nil {
return nil, err
}
return netsshConnToNetConnAdatper{c}, nil
return netsshConnToNetConnAdatper{c, l.clientIdentity}, nil
}
func (l StdinserverListener) Close() (err error) {
func (l stdinserverListener) Close() (err error) {
return l.l.Close()
}
@@ -66,12 +145,16 @@ func (netsshAddr) String() string { return "???" }
type netsshConnToNetConnAdatper struct {
io.ReadWriteCloser // works for both netssh.SSHConn and netssh.ServeConn
clientIdentity string
}
func (a netsshConnToNetConnAdatper) ClientIdentity() string { return a.clientIdentity }
func (netsshConnToNetConnAdatper) LocalAddr() net.Addr { return netsshAddr{} }
func (netsshConnToNetConnAdatper) RemoteAddr() net.Addr { return netsshAddr{} }
// FIXME log warning once!
func (netsshConnToNetConnAdatper) SetDeadline(t time.Time) error { return nil }
func (netsshConnToNetConnAdatper) SetReadDeadline(t time.Time) error { return nil }