Fix client session rotate logic

This commit is contained in:
wweir
2018-11-25 22:04:31 +08:00
parent aec2302339
commit c97bff0129
+49 -24
View File
@@ -3,6 +3,8 @@ package proxy
import (
"crypto/tls"
"net"
"sync/atomic"
"time"
"github.com/golang/glog"
"github.com/lucas-clemente/quic-go"
@@ -10,8 +12,10 @@ import (
func StartClient(server string) {
connCh := listenLocal([]string{":80", ":443"})
reDialCh := make(chan net.Conn, 10)
var conn net.Conn
for conn := range connCh {
for {
sess, err := quic.DialAddr(server, &tls.Config{InsecureSkipVerify: true}, nil)
if err != nil {
if sess, err = quic.DialAddr(server, &tls.Config{InsecureSkipVerify: true}, nil); err != nil {
@@ -21,18 +25,55 @@ func StartClient(server string) {
}
glog.Infoln("new session to", sess.RemoteAddr())
reDial := false // no cas action, no need add lock
for !reDial {
go openStream(conn, sess, &reDial)
conn = <-connCh
}
for { // session rotate logic
select {
case conn = <-connCh:
case conn = <-reDialCh:
}
sess.Close()
if !openStream(conn, sess, reDialCh) {
sess.Close()
break
}
}
}
}
func openStream(conn net.Conn, sess quic.Session, reDialCh chan<- net.Conn) bool {
glog.V(1).Infoln("new request from", conn.RemoteAddr())
sessStat := new(int32) // 0:waiting 1:ok 2:timeout
go func() {
stream, err := sess.OpenStream()
if err != nil {
glog.Warningf("connect to remote(%s) fail:%s\n", sess.RemoteAddr(), err)
reDialCh <- conn
return
}
defer stream.Close()
if !atomic.CompareAndSwapInt32(sessStat, 0, 1) {
reDialCh <- conn // timeout
}
conn.(*net.TCPConn).SetKeepAlive(true)
relay(&streamConn{stream, sess}, conn)
conn.Close()
}()
// wait timeout: 10ms * 100 => 1s
for i := 0; i < 100; i++ {
if atomic.LoadInt32(sessStat) == 1 {
return true
}
time.Sleep(10 * time.Millisecond)
}
return !atomic.CompareAndSwapInt32(sessStat, 0, 2)
}
func listenLocal(ports []string) <-chan net.Conn {
connCh := make(chan net.Conn)
connCh := make(chan net.Conn, 10)
for i := range ports {
go func(port string) {
ln, err := net.Listen("tcp", port)
@@ -54,19 +95,3 @@ func listenLocal(ports []string) <-chan net.Conn {
glog.Infoln("listening ports:", ports)
return connCh
}
func openStream(conn net.Conn, sess quic.Session, reDial *bool) {
defer conn.Close()
conn.(*net.TCPConn).SetKeepAlive(true)
glog.V(1).Infoln("new request from", conn.RemoteAddr())
stream, err := sess.OpenStream()
if err != nil {
glog.Warningf("connect to remote(%s) fail:%s\n", sess.RemoteAddr(), err)
*reDial = true
return
}
defer stream.Close()
relay(&streamConn{stream, sess}, conn)
}