diff --git a/agent/agent.go b/agent/agent.go index f7c5598b7b710..ffaf2ed454c66 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -879,12 +879,22 @@ func (r *reconnectingPTY) Close() { // after one or both of them are done writing. If the context is canceled, both // of the connections will be closed. func Bicopy(ctx context.Context, c1, c2 io.ReadWriteCloser) { - defer c1.Close() - defer c2.Close() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + defer func() { + _ = c1.Close() + _ = c2.Close() + }() var wg sync.WaitGroup copyFunc := func(dst io.WriteCloser, src io.Reader) { - defer wg.Done() + defer func() { + wg.Done() + // If one side of the copy fails, ensure the other one exits as + // well. + cancel() + }() _, _ = io.Copy(dst, src) } diff --git a/cli/portforward.go b/cli/portforward.go index 5a6f4391dd897..911e8fb5208d7 100644 --- a/cli/portforward.go +++ b/cli/portforward.go @@ -138,8 +138,7 @@ func portForward() *cobra.Command { case <-ctx.Done(): closeErr = ctx.Err() case <-sigs: - _, _ = fmt.Fprintln(cmd.OutOrStderr(), "Received signal, closing all listeners and active connections") - closeErr = xerrors.New("signal received") + _, _ = fmt.Fprintln(cmd.OutOrStderr(), "\nReceived signal, closing all listeners and active connections") } cancel() @@ -213,7 +212,11 @@ func listenAndPortForward(ctx context.Context, cmd *cobra.Command, conn *codersd for { netConn, err := l.Accept() if err != nil { - _, _ = fmt.Fprintf(cmd.OutOrStderr(), "Error accepting connection from '%v://%v': %+v\n", spec.listenNetwork, spec.listenAddress, err) + // Silently ignore net.ErrClosed errors. + if xerrors.Is(err, net.ErrClosed) { + return + } + _, _ = fmt.Fprintf(cmd.OutOrStderr(), "Error accepting connection from '%v://%v': %v\n", spec.listenNetwork, spec.listenAddress, err) _, _ = fmt.Fprintln(cmd.OutOrStderr(), "Killing listener") return }