init: 自 zomaintain/backend/zonat 平移独立成库; module path 改为 git.zeroonesoft.cn/golib/zonat; 内部 import 同步重写
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"git.zeroonesoft.cn/golib/zonat/agent"
|
||||
)
|
||||
|
||||
// TunnelServer 一条已注册隧道的公网侧监听。
|
||||
// 纯 TCP 字节管道:无协议嗅探、无 HTTP 代理、无证书,任何 TCP 协议原样通过。
|
||||
type TunnelServer struct {
|
||||
tunnel agent.Tunnel
|
||||
session *Session
|
||||
listener net.Listener
|
||||
|
||||
connCount atomic.Int64
|
||||
lastActive atomic.Int64 // unix nano
|
||||
closed atomic.Bool
|
||||
}
|
||||
|
||||
// Port 公网监听端口
|
||||
func (t *TunnelServer) Port() int { return t.tunnel.ListenPort }
|
||||
|
||||
func (t *TunnelServer) touch() { t.lastActive.Store(time.Now().UnixNano()) }
|
||||
|
||||
func (t *TunnelServer) lastActiveTime() time.Time {
|
||||
return time.Unix(0, t.lastActive.Load())
|
||||
}
|
||||
|
||||
func (t *TunnelServer) acceptLoop() {
|
||||
for {
|
||||
conn, err := t.listener.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if t.closed.Load() {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
go t.handleConn(conn)
|
||||
}
|
||||
}
|
||||
|
||||
// handleConn 公网连接 → smux 新流 → 首帧告知目标 → agent 回执后双向管道。
|
||||
// 与 zonat 多路复用路径一致,仅去掉协议嗅探与限流。
|
||||
func (t *TunnelServer) handleConn(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
if t.session.isDead() {
|
||||
return
|
||||
}
|
||||
stream, err := t.session.OpenStream()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
tf := agent.NewFrame(agent.FrameVersion, agent.CmdTarget, 0)
|
||||
if err := tf.Marshal(t.tunnel); err != nil {
|
||||
return
|
||||
}
|
||||
if err := agent.WriteFrame(stream, tf); err != nil {
|
||||
return
|
||||
}
|
||||
rf, err := agent.ReadFrame(stream)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ret := agent.Ret{}
|
||||
if err := rf.Unmarshal(&ret); err != nil || ret.Code != 0 {
|
||||
slog.Warn("节点 agent拨号失败", "id", t.tunnel.Id, "msg", ret.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
// 公网侧 TCP 保活(smux 流自身由会话级 keepalive 保护)
|
||||
if tc, ok := conn.(*net.TCPConn); ok {
|
||||
tc.SetKeepAlive(true)
|
||||
tc.SetKeepAlivePeriod(5 * time.Second)
|
||||
}
|
||||
t.connCount.Add(1)
|
||||
t.touch()
|
||||
defer func() {
|
||||
t.connCount.Add(-1)
|
||||
t.touch()
|
||||
}()
|
||||
|
||||
pipe(conn, stream)
|
||||
}
|
||||
|
||||
func (t *TunnelServer) close() {
|
||||
if t.closed.CompareAndSwap(false, true) && t.listener != nil {
|
||||
t.listener.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// pipe 双向拷贝,任一方向结束即关闭两端
|
||||
func pipe(a, b net.Conn) {
|
||||
go func() {
|
||||
io.Copy(b, a)
|
||||
b.Close()
|
||||
}()
|
||||
io.Copy(a, b)
|
||||
a.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user