2

I am building a TCP proxy with go, but I am facing a small problem. Before actually handling the connection c1 and forwarding it to c2, I want to do some checks. To do this, I need the string representation of the byte slice from c1. Unfortunately, _, err := io.CopyBuffer(w, r, buf) is copying the []byte directly between the writer and reader, and if I do c1.Read() before the cp function, the []byte have already been read.

Here is the function containing the connection handling:

 func (p *proxy) handle(c1 net.Conn) {
        p.log.Printf("accepted %v", c1.RemoteAddr())
        defer p.log.Printf("disconnected %v", c1.RemoteAddr())
        defer c1.Close()
        c2, err := dialer.Dial("tcp", p.dial)
        log.Println("DIAL:", p.dial)
        if err != nil {
            p.log.Print("C2", err)
            return
        }
        defer c2.Close()

        errc := make(chan error, 2)
        cp := func(w io.Writer, r io.Reader) {
            buf := bufferPool.Get().([]byte)
            _, err := io.CopyBuffer(w, r, buf)
            errc <- err
            bufferPool.Put(buf)
        }
        go cp(struct{ io.Writer }{c1}, c2)
        go cp(c2, struct{ io.Reader }{c1})
        err = <-errc
        if err != nil {
            p.log.Print("F-ERROR ->", err)
        }
    }

Is there a way to "duplicate" the []byte so that I can use the duplicate to display as a string?

ChaChaPoly
  • 1,811
  • 5
  • 17
  • 39
  • 1
    Related / possible duplicate: [Golang read request body](https://stackoverflow.com/questions/43021058/golang-read-request-body/43021236#43021236) – icza Sep 17 '18 at 13:18

1 Answers1

3

You can use io.MultiReader to concatenate two or more readers. So you can Read() from c1, and then use a MultiReader to "replay" the bytes you already read.

package main

import (
    "bytes"
    "io"
    "log"
    "net"
)

func main() {
    var c1, c2 net.Conn

    buf := make([]byte, 64)
    n, err := c1.Read(buf)
    buf = buf[:n]
    if err != nil {
        log.Fatal(err)
    }

    // TODO: deal with string(buf)

    errc := make(chan error, 2)

    go func() {
        // Replay contents of buf, then copy the unread part of c1.
        _, err := io.Copy(c2, io.MultiReader(bytes.NewReader(buf), c1))
        errc <- err
    }()

    go func() {
        _, err := io.Copy(c1, c2)
        errc <- err
    }()

    err = <-errc
    log.Println(err)
}

Alternatively, simply Write() the bytes before starting to copy:

    go func() {
        // Replay contents of buf
        _, err := c2.Write(buf)
        if err != nil {
            errc <- err
            return
        }

        _, err = io.Copy(c2, c1)
        errc <- err
    }()
Peter
  • 29,454
  • 5
  • 48
  • 60