mirror of
https://github.com/wweir/sower.git
synced 2024-04-21 12:42:15 +00:00
110 lines
2.2 KiB
Go
110 lines
2.2 KiB
Go
package proxy
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/lucas-clemente/quic-go"
|
|
)
|
|
|
|
func StartClient(server string) {
|
|
connCh := listenLocal([]string{":80", ":443"})
|
|
reDialCh := make(chan net.Conn, 10)
|
|
var conn net.Conn
|
|
var count int
|
|
|
|
for {
|
|
sess, err := quic.DialAddr(server, &tls.Config{InsecureSkipVerify: true}, dialConf)
|
|
if err != nil {
|
|
if sess, err = quic.DialAddr(server, &tls.Config{InsecureSkipVerify: true}, dialConf); err != nil {
|
|
glog.Errorf("connect to remote(%s) fail:%s\n", server, err)
|
|
time.Sleep(2 * time.Second)
|
|
continue
|
|
}
|
|
}
|
|
glog.Infof("new session from (%s) to (%s)", sess.LocalAddr(), sess.RemoteAddr())
|
|
|
|
count = 0
|
|
for { // session rotate logic
|
|
select {
|
|
case conn = <-connCh:
|
|
case conn = <-reDialCh:
|
|
}
|
|
count++
|
|
|
|
// sync action to reuse sigle sess
|
|
if !openStream(conn, sess, count, reDialCh) {
|
|
sess.Close()
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func openStream(conn net.Conn, sess quic.Session, count int, reDialCh chan<- net.Conn) bool {
|
|
glog.V(2).Infoln("new request from", conn.RemoteAddr())
|
|
|
|
okCh := make(chan struct{})
|
|
go func() {
|
|
stream, err := sess.OpenStream()
|
|
if err != nil {
|
|
glog.Warningf("start stream to (%s) fail:%s\n", sess.RemoteAddr(), err)
|
|
reDialCh <- conn
|
|
close(okCh)
|
|
return
|
|
}
|
|
defer stream.Close()
|
|
|
|
glog.V(2).Infof("START stream\t%d", count)
|
|
defer glog.V(2).Infof("CLOSE stream\t%d", count)
|
|
|
|
select {
|
|
case okCh <- struct{}{}:
|
|
default:
|
|
close(okCh)
|
|
return
|
|
}
|
|
close(okCh)
|
|
|
|
if err := conn.(*net.TCPConn).SetKeepAlive(true); err != nil {
|
|
glog.Warningln(err)
|
|
}
|
|
relay(sess, &streamConn{stream, sess}, conn)
|
|
conn.Close()
|
|
}()
|
|
|
|
select {
|
|
case _, ok := <-okCh: // false means close on error
|
|
return ok
|
|
case <-time.After(500 * time.Millisecond):
|
|
return false
|
|
}
|
|
}
|
|
|
|
func listenLocal(ports []string) <-chan net.Conn {
|
|
connCh := make(chan net.Conn, 10)
|
|
for i := range ports {
|
|
go func(port string) {
|
|
ln, err := net.Listen("tcp", port)
|
|
if err != nil {
|
|
glog.Fatalln(err)
|
|
}
|
|
|
|
for {
|
|
conn, err := ln.Accept()
|
|
if err != nil {
|
|
glog.Errorln("accept", port, "fail:", err)
|
|
continue
|
|
}
|
|
|
|
connCh <- conn
|
|
}
|
|
}(ports[i])
|
|
}
|
|
|
|
glog.Infoln("listening ports:", ports)
|
|
return connCh
|
|
}
|