优化udp代理
This commit is contained in:
@ -124,7 +124,7 @@ func initConfig() (err error) {
|
||||
httpArgs.Debug = isDebug
|
||||
//########tcp#########
|
||||
tcp := app.Command("tcp", "proxy on tcp mode")
|
||||
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("[]").Short('P').String()
|
||||
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
|
||||
@ -136,7 +136,7 @@ func initConfig() (err error) {
|
||||
|
||||
//########udp#########
|
||||
udp := app.Command("udp", "proxy on udp mode")
|
||||
udpArgs.Parent = udp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("[]").Short('P').String()
|
||||
udpArgs.Parent = udp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
udpArgs.CertFile = udp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int()
|
||||
|
||||
@ -192,24 +192,22 @@ func snapshot(m ConcurrentMap) (chans []chan Tuple) {
|
||||
wg.Add(SHARD_COUNT)
|
||||
// Foreach shard.
|
||||
for index, shard := range m {
|
||||
go func() {
|
||||
go func(index int, shard *ConcurrentMapShared) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
func(index int, shard *ConcurrentMapShared) {
|
||||
// Foreach key, value pair.
|
||||
shard.RLock()
|
||||
chans[index] = make(chan Tuple, len(shard.items))
|
||||
wg.Done()
|
||||
for key, val := range shard.items {
|
||||
chans[index] <- Tuple{key, val}
|
||||
}
|
||||
shard.RUnlock()
|
||||
close(chans[index])
|
||||
}(index, shard)
|
||||
}()
|
||||
// Foreach key, value pair.
|
||||
shard.RLock()
|
||||
chans[index] = make(chan Tuple, len(shard.items))
|
||||
wg.Done()
|
||||
for key, val := range shard.items {
|
||||
chans[index] <- Tuple{key, val}
|
||||
}
|
||||
shard.RUnlock()
|
||||
close(chans[index])
|
||||
}(index, shard)
|
||||
}
|
||||
wg.Wait()
|
||||
return chans
|
||||
|
||||
@ -143,7 +143,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
||||
httpArgs.Debug = debug
|
||||
//########tcp#########
|
||||
tcp := app.Command("tcp", "proxy on tcp mode")
|
||||
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("[]").Short('P').String()
|
||||
tcpArgs.Parent = tcp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
tcpArgs.CertFile = tcp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
tcpArgs.KeyFile = tcp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
tcpArgs.Timeout = tcp.Flag("timeout", "tcp timeout milliseconds when connect to real server or parent proxy").Short('e').Default("2000").Int()
|
||||
@ -155,7 +155,7 @@ func StartWithLog(serviceID, serviceArgsStr string, loggerCallback LogCallback)
|
||||
|
||||
//########udp#########
|
||||
udp := app.Command("udp", "proxy on udp mode")
|
||||
udpArgs.Parent = udp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("[]").Short('P').String()
|
||||
udpArgs.Parent = udp.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
|
||||
udpArgs.CertFile = udp.Flag("cert", "cert file for tls").Short('C').Default("proxy.crt").String()
|
||||
udpArgs.KeyFile = udp.Flag("key", "key file for tls").Short('K').Default("proxy.key").String()
|
||||
udpArgs.Timeout = udp.Flag("timeout", "tcp timeout milliseconds when connect to parent proxy").Short('t').Default("2000").Int()
|
||||
|
||||
@ -182,11 +182,6 @@ func NewMuxServer() services.Service {
|
||||
}
|
||||
}
|
||||
|
||||
type MuxUDPPacketItem struct {
|
||||
packet *[]byte
|
||||
localAddr *net.UDPAddr
|
||||
srcAddr *net.UDPAddr
|
||||
}
|
||||
type MuxUDPConnItem struct {
|
||||
conn *net.Conn
|
||||
touchtime int64
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
logger "log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/snail007/goproxy/services"
|
||||
@ -33,7 +33,15 @@ type TCPArgs struct {
|
||||
KCP kcpcfg.KCPConfigArgs
|
||||
Jumper *string
|
||||
}
|
||||
|
||||
type UDPConnItem struct {
|
||||
conn *net.Conn
|
||||
isActive bool
|
||||
touchtime int64
|
||||
srcAddr *net.UDPAddr
|
||||
localAddr *net.UDPAddr
|
||||
udpConn *net.UDPConn
|
||||
connid string
|
||||
}
|
||||
type TCP struct {
|
||||
cfg TCPArgs
|
||||
sc *utils.ServerChannel
|
||||
@ -41,6 +49,7 @@ type TCP struct {
|
||||
userConns mapx.ConcurrentMap
|
||||
log *logger.Logger
|
||||
jumper *jumper.Jumper
|
||||
udpConns mapx.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewTCP() services.Service {
|
||||
@ -48,6 +57,7 @@ func NewTCP() services.Service {
|
||||
cfg: TCPArgs{},
|
||||
isStop: false,
|
||||
userConns: mapx.NewConcurrentMap(),
|
||||
udpConns: mapx.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
func (s *TCP) CheckArgs() (err error) {
|
||||
@ -81,7 +91,7 @@ func (s *TCP) CheckArgs() (err error) {
|
||||
return
|
||||
}
|
||||
func (s *TCP) InitService() (err error) {
|
||||
|
||||
s.UDPGCDeamon()
|
||||
return
|
||||
}
|
||||
func (s *TCP) StopService() {
|
||||
@ -158,12 +168,14 @@ func (s *TCP) callback(inConn net.Conn) {
|
||||
case "tls":
|
||||
err = s.OutToTCP(&inConn)
|
||||
case "udp":
|
||||
err = s.OutToUDP(&inConn)
|
||||
s.OutToUDP(&inConn)
|
||||
default:
|
||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||
}
|
||||
if err != nil {
|
||||
s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, lbAddr, err)
|
||||
if !utils.IsNetClosedErr(err) {
|
||||
s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, lbAddr, err)
|
||||
}
|
||||
utils.CloseConn(&inConn)
|
||||
}
|
||||
}
|
||||
@ -192,56 +204,136 @@ func (s *TCP) OutToTCP(inConn *net.Conn) (err error) {
|
||||
return
|
||||
}
|
||||
func (s *TCP) OutToUDP(inConn *net.Conn) (err error) {
|
||||
s.log.Printf("conn created , remote : %s ", (*inConn).RemoteAddr())
|
||||
var item *UDPConnItem
|
||||
var body []byte
|
||||
srcAddr := ""
|
||||
defer func() {
|
||||
if item != nil {
|
||||
(*(*item).conn).Close()
|
||||
(*item).udpConn.Close()
|
||||
s.udpConns.Remove(srcAddr)
|
||||
(*inConn).Close()
|
||||
}
|
||||
}()
|
||||
for {
|
||||
if s.isStop {
|
||||
(*inConn).Close()
|
||||
return
|
||||
}
|
||||
srcAddr, body, err := utils.ReadUDPPacket(bufio.NewReader(*inConn))
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
//s.log.Printf("connection %s released", srcAddr)
|
||||
utils.CloseConn(inConn)
|
||||
break
|
||||
}
|
||||
//log.Debugf("udp packet revecived:%s,%v", srcAddr, body)
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
|
||||
var srcAddr string
|
||||
srcAddr, body, err = utils.ReadUDPPacket(*inConn)
|
||||
if err != nil {
|
||||
s.log.Printf("can't resolve address: %s", err)
|
||||
utils.CloseConn(inConn)
|
||||
break
|
||||
if strings.Contains(err.Error(), "n != int(") {
|
||||
continue
|
||||
}
|
||||
if !utils.IsNetDeadlineErr(err) && err != io.EOF && !utils.IsNetClosedErr(err) {
|
||||
s.log.Printf("udp packet revecived from client fail, err: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||
if err != nil {
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
continue
|
||||
localAddr := *s.cfg.Parent
|
||||
if v, ok := s.udpConns.Get(srcAddr); !ok {
|
||||
_srcAddr, _ := net.ResolveUDPAddr("udp", srcAddr)
|
||||
zeroAddr, _ := net.ResolveUDPAddr("udp", ":")
|
||||
_localAddr, _ := net.ResolveUDPAddr("udp", localAddr)
|
||||
var c *net.UDPConn
|
||||
c, err = net.DialUDP("udp", zeroAddr, _localAddr)
|
||||
if err != nil {
|
||||
s.log.Printf("create local udp conn fail, err : %s", err)
|
||||
(*inConn).Close()
|
||||
return
|
||||
}
|
||||
item = &UDPConnItem{
|
||||
conn: inConn,
|
||||
srcAddr: _srcAddr,
|
||||
localAddr: _localAddr,
|
||||
udpConn: c,
|
||||
}
|
||||
s.udpConns.Set(srcAddr, item)
|
||||
s.UDPRevecive(srcAddr)
|
||||
} else {
|
||||
item = v.(*UDPConnItem)
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(body)
|
||||
if err != nil {
|
||||
s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||
continue
|
||||
}
|
||||
//log.Debugf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 512)
|
||||
len, _, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
continue
|
||||
}
|
||||
respBody := buf[0:len]
|
||||
//log.Debugf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
||||
_, err = (*inConn).Write(utils.UDPPacket(srcAddr, respBody))
|
||||
if err != nil {
|
||||
s.log.Printf("send udp response fail ,ERR:%s", err)
|
||||
utils.CloseConn(inConn)
|
||||
break
|
||||
}
|
||||
//s.log.Printf("send udp response success ,from:%s", dstAddr.String())
|
||||
(*item).touchtime = time.Now().Unix()
|
||||
go (*item).udpConn.Write(body)
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
func (s *TCP) UDPRevecive(key string) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
s.log.Printf("udp conn %s connected", key)
|
||||
v, ok := s.udpConns.Get(key)
|
||||
if !ok {
|
||||
s.log.Printf("[warn] udp conn not exists for %s", key)
|
||||
return
|
||||
}
|
||||
cui := v.(*UDPConnItem)
|
||||
buf := utils.LeakyBuffer.Get()
|
||||
defer func() {
|
||||
utils.LeakyBuffer.Put(buf)
|
||||
(*cui.conn).Close()
|
||||
cui.udpConn.Close()
|
||||
s.udpConns.Remove(key)
|
||||
s.log.Printf("udp conn %s released", key)
|
||||
}()
|
||||
for {
|
||||
n, err := cui.udpConn.Read(buf)
|
||||
if err != nil {
|
||||
if !utils.IsNetClosedErr(err) {
|
||||
s.log.Printf("udp conn read udp packet fail , err: %s ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
cui.touchtime = time.Now().Unix()
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
(*cui.conn).SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = (*cui.conn).Write(utils.UDPPacket(cui.srcAddr.String(), buf[:n]))
|
||||
(*cui.conn).SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
cui.udpConn.Close()
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
func (s *TCP) UDPGCDeamon() {
|
||||
gctime := int64(30)
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
timer := time.NewTicker(time.Second)
|
||||
for {
|
||||
<-timer.C
|
||||
gcKeys := []string{}
|
||||
s.udpConns.IterCb(func(key string, v interface{}) {
|
||||
if time.Now().Unix()-v.(*UDPConnItem).touchtime > gctime {
|
||||
(*(v.(*UDPConnItem).conn)).Close()
|
||||
(v.(*UDPConnItem).udpConn).Close()
|
||||
gcKeys = append(gcKeys, key)
|
||||
s.log.Printf("gc udp conn %s", key)
|
||||
}
|
||||
})
|
||||
for _, k := range gcKeys {
|
||||
s.udpConns.Remove(k)
|
||||
}
|
||||
gcKeys = nil
|
||||
}
|
||||
}()
|
||||
}
|
||||
func (s *TCP) GetParentConn() (conn net.Conn, err error) {
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
package udp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
logger "log"
|
||||
"net"
|
||||
@ -30,17 +28,35 @@ type UDPArgs struct {
|
||||
CheckParentInterval *int
|
||||
}
|
||||
type UDP struct {
|
||||
p mapx.ConcurrentMap
|
||||
cfg UDPArgs
|
||||
sc *utils.ServerChannel
|
||||
isStop bool
|
||||
log *logger.Logger
|
||||
p mapx.ConcurrentMap
|
||||
cfg UDPArgs
|
||||
sc *utils.ServerChannel
|
||||
isStop bool
|
||||
log *logger.Logger
|
||||
outUDPConnCtxMap mapx.ConcurrentMap
|
||||
udpConns mapx.ConcurrentMap
|
||||
dstAddr *net.UDPAddr
|
||||
}
|
||||
type UDPConnItem struct {
|
||||
conn *net.Conn
|
||||
touchtime int64
|
||||
srcAddr *net.UDPAddr
|
||||
localAddr *net.UDPAddr
|
||||
connid string
|
||||
}
|
||||
type outUDPConnCtx struct {
|
||||
localAddr *net.UDPAddr
|
||||
srcAddr *net.UDPAddr
|
||||
udpconn *net.UDPConn
|
||||
touchtime int64
|
||||
}
|
||||
|
||||
func NewUDP() services.Service {
|
||||
return &UDP{
|
||||
p: mapx.NewConcurrentMap(),
|
||||
isStop: false,
|
||||
p: mapx.NewConcurrentMap(),
|
||||
isStop: false,
|
||||
outUDPConnCtxMap: mapx.NewConcurrentMap(),
|
||||
udpConns: mapx.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
func (s *UDP) CheckArgs() (err error) {
|
||||
@ -49,7 +65,7 @@ func (s *UDP) CheckArgs() (err error) {
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "" {
|
||||
err = fmt.Errorf("parent type unkown,use -T <tls|tcp>")
|
||||
err = fmt.Errorf("parent type unkown,use -T <udp|tls|tcp>")
|
||||
return
|
||||
}
|
||||
if *s.cfg.ParentType == "tls" {
|
||||
@ -58,10 +74,17 @@ func (s *UDP) CheckArgs() (err error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s.dstAddr, err = net.ResolveUDPAddr("udp", *s.cfg.Parent)
|
||||
if err != nil {
|
||||
s.log.Printf("resolve udp addr %s fail fail,ERR:%s", *s.cfg.Parent, err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *UDP) InitService() (err error) {
|
||||
|
||||
s.OutToUDPGCDeamon()
|
||||
s.UDPGCDeamon()
|
||||
return
|
||||
}
|
||||
func (s *UDP) StopService() {
|
||||
@ -117,19 +140,15 @@ func (s *UDP) callback(listener *net.UDPConn, packet []byte, localAddr, srcAddr
|
||||
s.log.Printf("udp conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
var err error
|
||||
switch *s.cfg.ParentType {
|
||||
case "tcp":
|
||||
fallthrough
|
||||
case "tls":
|
||||
err = s.OutToTCP(packet, localAddr, srcAddr)
|
||||
s.OutToTCP(packet, localAddr, srcAddr)
|
||||
case "udp":
|
||||
err = s.OutToUDP(packet, localAddr, srcAddr)
|
||||
s.OutToUDP(packet, localAddr, srcAddr)
|
||||
default:
|
||||
err = fmt.Errorf("unkown parent type %s", *s.cfg.ParentType)
|
||||
}
|
||||
if err != nil {
|
||||
s.log.Printf("connect to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
||||
s.log.Printf("unkown parent type %s", *s.cfg.ParentType)
|
||||
}
|
||||
}
|
||||
func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
|
||||
@ -147,104 +166,97 @@ func (s *UDP) GetConn(connKey string) (conn net.Conn, isNew bool, err error) {
|
||||
conn = _conn.(net.Conn)
|
||||
return
|
||||
}
|
||||
func (s *UDP) OutToTCP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
|
||||
numLocal := crc32.ChecksumIEEE([]byte(localAddr.String()))
|
||||
numSrc := crc32.ChecksumIEEE([]byte(srcAddr.String()))
|
||||
mod := uint32(10)
|
||||
if mod == 0 {
|
||||
mod = 10
|
||||
}
|
||||
connKey := uint64((numLocal/10)*10 + numSrc%mod)
|
||||
conn, isNew, err := s.GetConn(fmt.Sprintf("%d", connKey))
|
||||
if err != nil {
|
||||
s.log.Printf("upd get conn to %s parent %s fail, ERR:%s", *s.cfg.ParentType, *s.cfg.Parent, err)
|
||||
return
|
||||
}
|
||||
if isNew {
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
s.log.Printf("udp conn handler out to tcp crashed with err : %s \nstack: %s", err, string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
s.log.Printf("conn %d created , local: %s", connKey, srcAddr.String())
|
||||
for {
|
||||
if s.isStop {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
srcAddrFromConn, body, err := utils.ReadUDPPacket(bufio.NewReader(conn))
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
//s.log.Printf("connection %d released", connKey)
|
||||
s.p.Remove(fmt.Sprintf("%d", connKey))
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
s.log.Printf("parse revecived udp packet fail, err: %s", err)
|
||||
continue
|
||||
}
|
||||
//s.log.Printf("udp packet revecived over parent , local:%s", srcAddrFromConn)
|
||||
_srcAddr := strings.Split(srcAddrFromConn, ":")
|
||||
if len(_srcAddr) != 2 {
|
||||
s.log.Printf("parse revecived udp packet fail, addr error : %s", srcAddrFromConn)
|
||||
continue
|
||||
}
|
||||
port, _ := strconv.Atoi(_srcAddr[1])
|
||||
dstAddr := &net.UDPAddr{IP: net.ParseIP(_srcAddr[0]), Port: port}
|
||||
_, err = s.sc.UDPListener.WriteToUDP(body, dstAddr)
|
||||
if err != nil {
|
||||
s.log.Printf("udp response to local %s fail,ERR:%s", srcAddr, err)
|
||||
continue
|
||||
}
|
||||
//s.log.Printf("udp response to local %s success", srcAddr)
|
||||
}
|
||||
}()
|
||||
}
|
||||
//s.log.Printf("select conn %d , local: %s", connKey, srcAddr.String())
|
||||
writer := bufio.NewWriter(conn)
|
||||
//fmt.Println(conn, writer)
|
||||
writer.Write(utils.UDPPacket(srcAddr.String(), packet))
|
||||
err = writer.Flush()
|
||||
if err != nil {
|
||||
s.log.Printf("write udp packet to %s fail ,flush err:%s", *s.cfg.Parent, err)
|
||||
return
|
||||
}
|
||||
//s.log.Printf("write packet %v", packet)
|
||||
func (s *UDP) OutToTCP(data []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
|
||||
s.UDPSend(data, localAddr, srcAddr)
|
||||
return
|
||||
}
|
||||
func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) (err error) {
|
||||
//s.log.Printf("udp packet revecived:%s,%v", srcAddr, packet)
|
||||
dstAddr, err := net.ResolveUDPAddr("udp", *s.cfg.Parent)
|
||||
if err != nil {
|
||||
s.log.Printf("resolve udp addr %s fail fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
func (s *UDP) OutToUDPGCDeamon() {
|
||||
gctime := int64(30)
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
timer := time.NewTicker(time.Second)
|
||||
for {
|
||||
<-timer.C
|
||||
gcKeys := []string{}
|
||||
s.outUDPConnCtxMap.IterCb(func(key string, v interface{}) {
|
||||
if time.Now().Unix()-v.(*outUDPConnCtx).touchtime > gctime {
|
||||
(*(v.(*outUDPConnCtx).udpconn)).Close()
|
||||
gcKeys = append(gcKeys, key)
|
||||
s.log.Printf("gc udp conn %s <--> %s", (*v.(*outUDPConnCtx)).srcAddr, (*v.(*outUDPConnCtx)).localAddr)
|
||||
}
|
||||
})
|
||||
for _, k := range gcKeys {
|
||||
s.outUDPConnCtxMap.Remove(k)
|
||||
}
|
||||
gcKeys = nil
|
||||
}
|
||||
}()
|
||||
}
|
||||
func (s *UDP) OutToUDP(packet []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
var ouc *outUDPConnCtx
|
||||
if v, ok := s.outUDPConnCtxMap.Get(srcAddr.String()); !ok {
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, s.dstAddr)
|
||||
if err != nil {
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", s.dstAddr.String(), err)
|
||||
|
||||
}
|
||||
ouc = &outUDPConnCtx{
|
||||
localAddr: localAddr,
|
||||
srcAddr: srcAddr,
|
||||
udpconn: conn,
|
||||
}
|
||||
s.outUDPConnCtxMap.Set(srcAddr.String(), ouc)
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
s.log.Printf("udp conn %s <--> %s connected", srcAddr.String(), localAddr.String())
|
||||
buf := utils.LeakyBuffer.Get()
|
||||
defer func() {
|
||||
utils.LeakyBuffer.Put(buf)
|
||||
s.outUDPConnCtxMap.Remove(srcAddr.String())
|
||||
s.log.Printf("udp conn %s <--> %s released", srcAddr.String(), localAddr.String())
|
||||
}()
|
||||
for {
|
||||
n, err := ouc.udpconn.Read(buf)
|
||||
if err != nil {
|
||||
if !utils.IsNetClosedErr(err) {
|
||||
s.log.Printf("udp conn read udp packet fail , err: %s ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
ouc.touchtime = time.Now().Unix()
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
(*(s.sc).UDPListener).SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = (*(s.sc).UDPListener).WriteTo(buf[:n], srcAddr)
|
||||
(*(s.sc).UDPListener).SetWriteDeadline(time.Time{})
|
||||
}()
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
ouc = v.(*outUDPConnCtx)
|
||||
}
|
||||
clientSrcAddr := &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
conn, err := net.DialUDP("udp", clientSrcAddr, dstAddr)
|
||||
if err != nil {
|
||||
s.log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = conn.Write(packet)
|
||||
if err != nil {
|
||||
s.log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
//s.log.Printf("send udp packet to %s success", dstAddr.String())
|
||||
buf := make([]byte, 512)
|
||||
len, _, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
s.log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
|
||||
return
|
||||
}
|
||||
//s.log.Printf("revecived udp packet from %s , %v", dstAddr.String(), respBody)
|
||||
_, err = s.sc.UDPListener.WriteToUDP(buf[0:len], srcAddr)
|
||||
if err != nil {
|
||||
s.log.Printf("send udp response to cluster fail ,ERR:%s", err)
|
||||
return
|
||||
}
|
||||
//s.log.Printf("send udp response to cluster success ,from:%s", dstAddr.String())
|
||||
go func() {
|
||||
ouc.touchtime = time.Now().Unix()
|
||||
ouc.udpconn.SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
ouc.udpconn.Write(packet)
|
||||
ouc.udpconn.SetWriteDeadline(time.Time{})
|
||||
}()
|
||||
return
|
||||
}
|
||||
func (s *UDP) GetParentConn() (conn net.Conn, err error) {
|
||||
@ -259,3 +271,126 @@ func (s *UDP) GetParentConn() (conn net.Conn, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
func (s *UDP) UDPGCDeamon() {
|
||||
gctime := int64(30)
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
if s.isStop {
|
||||
return
|
||||
}
|
||||
timer := time.NewTicker(time.Second)
|
||||
for {
|
||||
<-timer.C
|
||||
gcKeys := []string{}
|
||||
s.udpConns.IterCb(func(key string, v interface{}) {
|
||||
if time.Now().Unix()-v.(*UDPConnItem).touchtime > gctime {
|
||||
(*(v.(*UDPConnItem).conn)).Close()
|
||||
gcKeys = append(gcKeys, key)
|
||||
s.log.Printf("gc udp conn %s", v.(*UDPConnItem).connid)
|
||||
}
|
||||
})
|
||||
for _, k := range gcKeys {
|
||||
s.udpConns.Remove(k)
|
||||
}
|
||||
gcKeys = nil
|
||||
}
|
||||
}()
|
||||
}
|
||||
func (s *UDP) UDPSend(data []byte, localAddr, srcAddr *net.UDPAddr) {
|
||||
var (
|
||||
uc *UDPConnItem
|
||||
key = srcAddr.String()
|
||||
err error
|
||||
outconn net.Conn
|
||||
)
|
||||
v, ok := s.udpConns.Get(key)
|
||||
if !ok {
|
||||
for {
|
||||
outconn, err = s.GetParentConn()
|
||||
if err != nil && strings.Contains(err.Error(), "can not connect at same time") {
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
s.log.Printf("connect to %s fail, err: %s", *s.cfg.Parent, err)
|
||||
return
|
||||
}
|
||||
uc = &UDPConnItem{
|
||||
conn: &outconn,
|
||||
srcAddr: srcAddr,
|
||||
localAddr: localAddr,
|
||||
}
|
||||
s.udpConns.Set(key, uc)
|
||||
s.UDPRevecive(key)
|
||||
} else {
|
||||
uc = v.(*UDPConnItem)
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
(*uc.conn).Close()
|
||||
s.udpConns.Remove(key)
|
||||
s.log.Printf("udp sender crashed with error : %s", e)
|
||||
}
|
||||
}()
|
||||
uc.touchtime = time.Now().Unix()
|
||||
(*uc.conn).SetWriteDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
|
||||
_, err = (*uc.conn).Write(utils.UDPPacket(fmt.Sprintf("%s", srcAddr.String()), data))
|
||||
(*uc.conn).SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
s.log.Printf("write udp packet to %s fail ,flush err:%s ", *s.cfg.Parent, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
func (s *UDP) UDPRevecive(key string) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
s.log.Printf("udp conn %s connected", key)
|
||||
var uc *UDPConnItem
|
||||
defer func() {
|
||||
if uc != nil {
|
||||
(*uc.conn).Close()
|
||||
}
|
||||
s.udpConns.Remove(key)
|
||||
s.log.Printf("udp conn %s released", key)
|
||||
}()
|
||||
v, ok := s.udpConns.Get(key)
|
||||
if !ok {
|
||||
s.log.Printf("[warn] udp conn not exists for %s, connid : %s", key)
|
||||
return
|
||||
}
|
||||
uc = v.(*UDPConnItem)
|
||||
for {
|
||||
_, body, err := utils.ReadUDPPacket(*uc.conn)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "n != int(") {
|
||||
continue
|
||||
}
|
||||
if err != io.EOF && !utils.IsNetClosedErr(err) {
|
||||
s.log.Printf("udp conn read udp packet fail , err: %s ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
uc.touchtime = time.Now().Unix()
|
||||
go func() {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
s.sc.UDPListener.WriteToUDP(body, uc.srcAddr)
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@ -192,24 +192,22 @@ func snapshot(m ConcurrentMap) (chans []chan Tuple) {
|
||||
wg.Add(SHARD_COUNT)
|
||||
// Foreach shard.
|
||||
for index, shard := range m {
|
||||
go func() {
|
||||
go func(index int, shard *ConcurrentMapShared) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
fmt.Printf("crashed:%s", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
func(index int, shard *ConcurrentMapShared) {
|
||||
// Foreach key, value pair.
|
||||
shard.RLock()
|
||||
chans[index] = make(chan Tuple, len(shard.items))
|
||||
wg.Done()
|
||||
for key, val := range shard.items {
|
||||
chans[index] <- Tuple{key, val}
|
||||
}
|
||||
shard.RUnlock()
|
||||
close(chans[index])
|
||||
}(index, shard)
|
||||
}()
|
||||
// Foreach key, value pair.
|
||||
shard.RLock()
|
||||
chans[index] = make(chan Tuple, len(shard.items))
|
||||
wg.Done()
|
||||
for key, val := range shard.items {
|
||||
chans[index] <- Tuple{key, val}
|
||||
}
|
||||
shard.RUnlock()
|
||||
close(chans[index])
|
||||
}(index, shard)
|
||||
}
|
||||
wg.Wait()
|
||||
return chans
|
||||
|
||||
Reference in New Issue
Block a user