Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Commit

Permalink
Getting rid of socat
Browse files Browse the repository at this point in the history
Signed-off-by: abhi <[email protected]>
  • Loading branch information
abhi committed Mar 24, 2018
1 parent 616831f commit 3049a7f
Showing 1 changed file with 20 additions and 36 deletions.
56 changes: 20 additions & 36 deletions pkg/server/sandbox_portforward.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ limitations under the License.
package server

import (
"bytes"
"fmt"
"io"
"os/exec"
"strings"
"net"
"sync"

"github.com/containernetworking/plugins/pkg/ns"
"github.com/pkg/errors"
Expand Down Expand Up @@ -58,46 +57,31 @@ func (c *criService) portForward(id string, port int32, stream io.ReadWriteClose
return errors.Errorf("failed to find network namespace fo sandbox %q in store", id)
}

socat, err := exec.LookPath("socat")
if err != nil {
return errors.Wrap(err, "failed to find socat")
}

// Check following links for meaning of the options:
// * socat: https://linux.die.net/man/1/socat
args := []string{"-", fmt.Sprintf("TCP4:localhost:%d", port)}
logrus.Infof("Executing port forwarding command: %s %s", socat, strings.Join(args, " "))
err = s.NetNS.GetNs().Do(func(_ ns.NetNS) error {
cmd := exec.Command(socat, args...)
cmd.Stdout = stream

stderr := new(bytes.Buffer)
cmd.Stderr = stderr

// If we use Stdin, command.Run() won't return until the goroutine that's copying
// from stream finishes. Unfortunately, if you have a client like telnet connected
// via port forwarding, as long as the user's telnet client is connected to the user's
// local listener that port forwarding sets up, the telnet session never exits. This
// means that even if socat has finished running, command.Run() won't ever return
// (because the client still has the connection and stream open).
//
// The work around is to use StdinPipe(), as Wait() (called by Run()) closes the pipe
// when the command (socat) exits.
in, err := cmd.StdinPipe()
var wg sync.WaitGroup
client, err := net.Dial("tcp4", fmt.Sprintf("localhost:%d", port))
if err != nil {
return errors.Wrap(err, "failed to create stdin pipe")
return errors.Wrap(err, "failed to dial")
}
defer client.Close()

wg.Add(1)
go func() {
if _, err := io.Copy(in, stream); err != nil {
logrus.WithError(err).Errorf("Failed to copy port forward input for %q port %d", id, port)
if _, err := io.Copy(client, stream); err != nil {
logrus.WithError(err).Errorf("Failed to copy port forward input from %q port %d", id, port)
}
in.Close()
logrus.Debugf("Finish copy port forward input for %q port %d: %v", id, port)
wg.Done()
}()
wg.Add(1)
go func() {
if _, err := io.Copy(stream, client); err != nil {
logrus.WithError(err).Errorf("Failed to copy port forward output for %q port %d", id, port)
}
wg.Done()
}()
wg.Wait()
logrus.Infof("Finish copy port forward input for %q port %d: %v", id, port)

if err := cmd.Run(); err != nil {
return errors.Wrapf(err, "socat command returns error, stderr: %q", stderr.String())
}
return nil
})
if err != nil {
Expand Down

0 comments on commit 3049a7f

Please sign in to comment.