func (tt *TunnelTest) addClient(ident string, cfg *tunnel.ClientConfig) error { if _, ok := tt.Clients[ident]; ok { return fmt.Errorf("tunnel %q is already being served", ident) } c, err := tunnel.NewClient(cfg) if err != nil { return err } done := make(chan struct{}) tt.Server.OnConnect(ident, func() error { close(done) return nil }) go c.Start() <-c.StartNotify() select { case <-time.After(10 * time.Second): return errors.New("timed out after 10s waiting on client to establish control conn") case <-done: } tt.Clients[ident] = c return nil }
// NewClient gives new, unstarted tunnel client for the given options. func NewClient(opts *ClientOptions) (*Client, error) { optsCopy := *opts if optsCopy.Log == nil { optsCopy.Log = logging.NewCustom("tunnelclient", optsCopy.Debug) } // TODO(rjeczalik): fix production to use WebSocket by default // // BUG(rjeczalik): starting a kite that is not registered to // kontrol will prevent the kite from updating it's keypair, // when it changes in kontrol - the only fix is to restart // kite process. k := kite.New("tunnelclient", "0.0.1") k.Config = optsCopy.Kite.Config.Copy() k.Config.Transport = config.WebSocket c := &Client{ kite: k, opts: &optsCopy, tunnelKiteURL: optsCopy.tunnelKiteURL(), stateChanges: make(chan *tunnel.ClientStateChange, 128), regserv: make(chan map[string]*Tunnel, 1), services: make(Services), routes: make(map[int]string), } // If VirtualHost was configured, try to connect to it first. if c.opts.LastVirtualHost != "" { c.tunnelKiteURL = fmt.Sprintf("http://%s/kite", c.opts.LastVirtualHost) c.connected = &RegisterResult{ VirtualHost: c.opts.LastVirtualHost, ServerAddr: c.opts.LastVirtualHost, } } c.kite.ClientFunc = httputil.ClientFunc(opts.Debug) cfg := &tunnel.ClientConfig{ FetchIdentifier: c.fetchIdent, FetchServerAddr: c.fetchServerAddr, FetchLocalAddr: c.fetchLocalAddr, LocalAddr: c.opts.LocalAddr, Debug: c.opts.Debug, Log: c.opts.Log.New("transport"), StateChanges: c.stateChanges, } client, err := tunnel.NewClient(cfg) if err != nil { return nil, err } c.client = client return c, nil }
func TestNoHost(t *testing.T) { tt, err := tunneltest.Serve(singleHTTP(handlerEchoHTTP)) if err != nil { t.Fatal(err) } defer tt.Close() noBackoff := backoff.NewConstantBackOff(time.Duration(-1)) unknown, err := tunnel.NewClient(&tunnel.ClientConfig{ Identifier: "unknown", ServerAddr: tt.ServerAddr().String(), Backoff: noBackoff, Debug: testing.Verbose(), }) if err != nil { t.Fatalf("client error: %s", err) } unknown.Start() defer unknown.Close() if err := tt.ServerStateRecorder.WaitTransition( tunnel.ClientUnknown, tunnel.ClientClosed, ); err != nil { t.Fatal(err) } unknown.Start() if err := tt.ServerStateRecorder.WaitTransition( tunnel.ClientClosed, tunnel.ClientClosed, ); err != nil { t.Fatal(err) } }