Example #1
0
func backchannel(ctx context.Context, conn *net.Conn) error {
	defer trace.End(trace.Begin("establish tether backchannel"))

	// HACK: currently RawConn dosn't implement timeout so throttle the spinning
	// it does implement the Timeout methods so the intermediary code can be written
	// to support it, but they are stub implementation in rawconn impl.

	// This needs to tick *faster* than the ticker in connection.go on the
	// portlayer side.  The PL sends the first syn and if this isn't waiting,
	// alignment will take a few rounds (or it may never happen).
	ticker := time.NewTicker(10 * time.Millisecond)
	for {
		select {
		case <-ticker.C:
			err := serial.HandshakeServer(ctx, *conn)
			if err == nil {
				return nil
			}
		case <-ctx.Done():
			(*conn).Close()
			ticker.Stop()
			return ctx.Err()
		}
	}
}
Example #2
0
// Start the server, make 200 client connections, test they connect, then Stop.
func TestAttachStartStop(t *testing.T) {
	log.SetLevel(log.InfoLevel)
	s := NewAttachServer("", -1)

	wg := &sync.WaitGroup{}

	dial := func() {
		wg.Add(1)
		c, err := net.Dial("tcp", s.l.Addr().String())
		assert.NoError(t, err)
		assert.NotNil(t, c)

		buf := make([]byte, 1)
		c.Read(buf)
		if !assert.Error(t, serial.HandshakeServer(context.Background(), c)) {
			return
		}

		if !assert.NoError(t, serial.HandshakeServer(context.Background(), c)) {
			return
		}

		wg.Done()
	}

	assert.NoError(t, s.Start())

	for i := 0; i < 200; i++ {
		go dial()
	}

	done := make(chan bool)
	go func() {
		wg.Wait()
		close(done)
	}()

	select {
	case <-done:
	case <-time.After(10 * time.Second):
		t.Fail()
	}
	assert.NoError(t, s.Stop())

	_, err := net.Dial("tcp", s.l.Addr().String())
	assert.Error(t, err)
}
Example #3
0
File: attach.go Project: vmware/vic
func backchannel(ctx context.Context, conn net.Conn) error {
	defer trace.End(trace.Begin("establish tether backchannel"))

	// HACK: currently RawConn dosn't implement timeout so throttle the spinning
	// it does implement the Timeout methods so the intermediary code can be written
	// to support it, but they are stub implementation in rawconn impl.

	// This needs to tick *faster* than the ticker in connection.go on the
	// portlayer side.  The PL sends the first syn and if this isn't waiting,
	// alignment will take a few rounds (or it may never happen).
	ticker := time.NewTicker(10 * time.Millisecond)
	defer ticker.Stop()

	// We run this in a separate goroutine because HandshakeServer
	// calls a Read on rawconn which is a blocking call which causes
	// the caller to block as well so this is the only way to cancel.
	// Calling Close() will unblock us and on the next tick we will
	// return ctx.Err()
	go func() {
		select {
		case <-ctx.Done():
			conn.Close()
		}
	}()

	for {
		select {
		case <-ticker.C:
			if ctx.Err() != nil {
				return ctx.Err()
			}
			deadline, ok := ctx.Deadline()
			if ok {
				conn.SetReadDeadline(deadline)
			}

			err := serial.HandshakeServer(conn)
			if err == nil {
				conn.SetReadDeadline(time.Time{})
				return nil
			}

			switch et := err.(type) {
			case *serial.HandshakeError:
				log.Debugf("HandshakeServer: %v", et)
			default:
				log.Errorf("HandshakeServer: %v", err)
			}
		}
	}
}
Example #4
0
// Start the server, make 200 client connections, test they connect, then Stop.
func TestAttachStartStop(t *testing.T) {
	log.SetLevel(log.InfoLevel)
	s := NewAttachServer("", -1)

	wg := &sync.WaitGroup{}

	dial := func() {
		defer wg.Done()

		c, err := net.Dial("tcp", s.l.Addr().String())
		assert.NoError(t, err)
		assert.NotNil(t, c)
		defer c.Close()

		buf := make([]byte, 1)
		c.SetReadDeadline(time.Now().Add(time.Second))
		c.Read(buf)

		// This will pass if the client has written a second syn packet by the time it's called. As such we set an
		// unbounded readdeadline on the connection.
		// We can assert behaviours that take a while, but cannot reliably assert behaviours that require fast scheduling
		// of lots of threads on all systems running the CI.
		c.SetReadDeadline(time.Time{})
		if !assert.NoError(t, serial.HandshakeServer(c), "Expected handshake to succeed on 2nd syn packet from client") {
			return
		}
	}

	assert.NoError(t, s.Start(true))

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go dial()
	}

	done := make(chan bool)
	go func() {
		wg.Wait()
		close(done)
	}()

	select {
	case <-done:
	case <-time.After(10 * time.Second):
		t.Fail()
	}
	assert.NoError(t, s.Stop())

	_, err := net.Dial("tcp", s.l.Addr().String())
	assert.Error(t, err)
}
Example #5
0
func backchannel(ctx context.Context, conn *net.Conn) error {

	// HACK: currently RawConn dosn't implement timeout so throttle the spinning
	ticker := time.NewTicker(50 * time.Millisecond)
	for {
		select {
		case <-ticker.C:
			err := serial.HandshakeServer(ctx, *conn)
			if err == nil {
				return nil
			}
		case <-ctx.Done():
			(*conn).Close()
			ticker.Stop()
			return ctx.Err()
		}
	}
}
Example #6
0
func TestAttachSshSession(t *testing.T) {
	log.SetLevel(log.InfoLevel)

	s := NewAttachServer("", -1)
	assert.NoError(t, s.Start())
	defer s.Stop()

	expectedID := "foo"

	// This should block until the ssh server returns its container ID
	wg := sync.WaitGroup{}
	go func() {
		wg.Add(1)
		defer wg.Done()
		_, err := s.connServer.Get(context.Background(), expectedID, 5*time.Second)
		if !assert.NoError(t, err) {
			return
		}
	}()

	// Dial the attach server.  This is a TCP client
	networkClientCon, err := net.Dial("tcp", s.l.Addr().String())
	if !assert.NoError(t, err) {
		return
	}

	if !assert.NoError(t, serial.HandshakeServer(context.Background(), networkClientCon)) {
		return
	}

	containerConfig := &ssh.ServerConfig{
		NoClientAuth: true,
	}

	signer, err := ssh.ParsePrivateKey(testdata.PEMBytes["dsa"])
	if !assert.NoError(t, err) {
		return
	}
	containerConfig.AddHostKey(signer)

	// create the SSH server on the client.  The attach server will ssh connect to this.
	sshConn, chans, reqs, err := ssh.NewServerConn(networkClientCon, containerConfig)
	if !assert.NoError(t, err) {
		return
	}
	defer sshConn.Close()

	// Service the incoming Channel channel.
	go func() {
		wg.Add(1)
		defer wg.Done()
		for req := range reqs {
			if req.Type == msgs.ContainersReq {
				msg := msgs.ContainersMsg{IDs: []string{expectedID}}
				req.Reply(true, msg.Marshal())
				break
			}
		}
	}()

	go func() {
		wg.Add(1)
		defer wg.Done()
		for ch := range chans {
			assert.Equal(t, ch.ChannelType(), attachChannelType)
			_, _, _ = ch.Accept()
			break
		}
	}()

	wg.Wait()
}