package main import ( "log" "crypto/tls" "net" ) const localAddr string = "127.0.0.1:9999" const remoteAddr string = "127.0.0.1:25500" const MaxConn int16 = 3 func proxyConn(conn net.Conn) { defer conn.Close() rAddr, err := net.ResolveTCPAddr("tcp", remoteAddr) if err != nil { log.Print(err) } conf := &tls.Config{ InsecureSkipVerify: true, } //rConn, err := net.DialTCP("tcp", nil, rAddr) rConn, err := tls.Dial("tcp", rAddr.String(), conf) if err != nil { log.Print(err) return } defer rConn.Close() // log.Printf("remoteAddr connected: %v\n", rAddr.String()) Pipe(conn, rConn) // log.Printf("proxyConn end: %v -> %v\n", conn.RemoteAddr(), rConn.RemoteAddr()) } func chanFromConn(conn net.Conn) chan []byte { c := make(chan []byte) go func() { b := make([]byte, 1024) for { n, err := conn.Read(b) if n > 0 { res := make([]byte, n) // Copy the buffer so it doesn't get changed while read by the recipient. copy(res, b[:n]) c <- res } if err != nil { c <- nil break } } }() return c } func Pipe(conn1 net.Conn, conn2 net.Conn) { chan1 := chanFromConn(conn1) chan2 := chanFromConn(conn2) for { select { case b1 := <-chan1: if b1 == nil { return } else { conn2.Write(b1) } case b2 := <-chan2: if b2 == nil { return } else { conn1.Write(b2) } } } } func main() { log.SetFlags(log.Lshortfile) log.Printf("Listening: %v -> %v\n\n", localAddr, remoteAddr) addr, err := net.ResolveTCPAddr("tcp", localAddr) if err != nil { panic(err) } listener, err := net.ListenTCP("tcp", addr) if err != nil { panic(err) } var i int16 = 0; count := make(chan int16, 1) for { log.Printf("wait accepted...\n") conn, err := listener.AcceptTCP() if err != nil { log.Print(err) } //go proxyConn(conn); //log.Printf("accepted: %v\n", conn.RemoteAddr()) select { case t := <- count: i += t // print("received ", i, "\n") default: } if i < MaxConn { i++ log.Printf("[%v/%v]accepted: %v\n", i, MaxConn, conn.RemoteAddr()) // Create a new goroutine which will call the connection handler and then free up the space. go func(connection net.Conn) { proxyConn(connection) // log.Printf("[%v/%v]Closed connection from %s\r\n", i, MaxConn, connection.RemoteAddr()) log.Printf("Closed connection from %s\r\n", connection.RemoteAddr()) select { case t := <- count: count <- t-1 default: count <- -1 } }(conn) }else{ conn.Close() // log.Printf("closed: %v\n", i) } } }