mirror of
https://github.com/ehang-io/nps.git
synced 2025-07-03 04:53:50 +00:00
P2p first version
This commit is contained in:
parent
204c53ddd3
commit
534d428c6d
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/cnlh/nps/lib/pool"
|
"github.com/cnlh/nps/lib/pool"
|
||||||
"github.com/cnlh/nps/lib/version"
|
"github.com/cnlh/nps/lib/version"
|
||||||
"github.com/cnlh/nps/server/tool"
|
"github.com/cnlh/nps/server/tool"
|
||||||
|
"github.com/cnlh/nps/vender/github.com/astaxie/beego"
|
||||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||||
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
|
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
|
||||||
"net"
|
"net"
|
||||||
@ -71,7 +72,6 @@ func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList map[int
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Bridge) StartTunnel() error {
|
func (s *Bridge) StartTunnel() error {
|
||||||
go s.linkCleanSession()
|
|
||||||
var err error
|
var err error
|
||||||
if s.tunnelType == "kcp" {
|
if s.tunnelType == "kcp" {
|
||||||
s.kcpListener, err = kcp.ListenWithOptions(":"+strconv.Itoa(s.TunnelPort), nil, 150, 3)
|
s.kcpListener, err = kcp.ListenWithOptions(":"+strconv.Itoa(s.TunnelPort), nil, 150, 3)
|
||||||
@ -209,10 +209,35 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
|
|||||||
go s.GetConfig(c)
|
go s.GetConfig(c)
|
||||||
case common.WORK_REGISTER:
|
case common.WORK_REGISTER:
|
||||||
go s.register(c)
|
go s.register(c)
|
||||||
case common.WORD_SECRET:
|
case common.WORK_SECRET:
|
||||||
if b, err := c.ReadLen(32); err == nil {
|
if b, err := c.ReadLen(32); err == nil {
|
||||||
s.SecretChan <- conn.NewSecret(string(b), c)
|
s.SecretChan <- conn.NewSecret(string(b), c)
|
||||||
}
|
}
|
||||||
|
case common.WORK_P2P:
|
||||||
|
//读取md5密钥
|
||||||
|
if b, err := c.ReadLen(32); err != nil {
|
||||||
|
return
|
||||||
|
} else if t := file.GetCsvDb().GetTaskByMd5Password(string(b)); t == nil {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
s.clientLock.Lock()
|
||||||
|
if v, ok := s.Client[t.Client.Id]; !ok {
|
||||||
|
logs.Error("未获取到对应客户端")
|
||||||
|
s.clientLock.Unlock()
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
logs.Warn("获取到对应客户端")
|
||||||
|
s.clientLock.Unlock()
|
||||||
|
//向密钥对应的客户端发送与服务端udp建立连接信息,地址,密钥
|
||||||
|
logs.Warn(v.signal.Write([]byte(common.NEW_UDP_CONN)))
|
||||||
|
svrAddr := beego.AppConfig.String("serverIp") + ":" + beego.AppConfig.String("p2pPort")
|
||||||
|
logs.Warn(svrAddr)
|
||||||
|
logs.Warn(v.signal.WriteLenContent([]byte(svrAddr)))
|
||||||
|
logs.Warn(string(b), v.signal.WriteLenContent(b))
|
||||||
|
//向该请求者发送建立连接请求,服务器地址
|
||||||
|
c.WriteLenContent([]byte(svrAddr))
|
||||||
|
}
|
||||||
|
}
|
||||||
case common.WORK_SEND_STATUS:
|
case common.WORK_SEND_STATUS:
|
||||||
s.clientLock.Lock()
|
s.clientLock.Lock()
|
||||||
if v, ok := s.Client[id]; ok {
|
if v, ok := s.Client[id]; ok {
|
||||||
@ -511,6 +536,7 @@ func (s *Bridge) clientCopy(clientId int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO 清除有一个未知bug待处理
|
||||||
func (s *Bridge) linkCleanSession() {
|
func (s *Bridge) linkCleanSession() {
|
||||||
ticker := time.NewTicker(time.Minute * 5)
|
ticker := time.NewTicker(time.Minute * 5)
|
||||||
for {
|
for {
|
||||||
@ -526,7 +552,7 @@ func (s *Bridge) linkCleanSession() {
|
|||||||
}
|
}
|
||||||
v.Unlock()
|
v.Unlock()
|
||||||
}
|
}
|
||||||
s.clientLock.RUnlock()
|
s.clientLock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
133
client/client.go
133
client/client.go
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/cnlh/nps/lib/conn"
|
"github.com/cnlh/nps/lib/conn"
|
||||||
"github.com/cnlh/nps/lib/pool"
|
"github.com/cnlh/nps/lib/pool"
|
||||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
@ -38,7 +39,6 @@ func NewRPClient(svraddr string, vKey string, bridgeConnType string, proxyUrl st
|
|||||||
|
|
||||||
//start
|
//start
|
||||||
func (s *TRPClient) Start() {
|
func (s *TRPClient) Start() {
|
||||||
go s.linkCleanSession()
|
|
||||||
retry:
|
retry:
|
||||||
c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
|
c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -82,8 +82,8 @@ func (s *TRPClient) processor(c *conn.Conn) {
|
|||||||
s.linkMap[link.Id] = link
|
s.linkMap[link.Id] = link
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
link.MsgConn = s.msgTunnel
|
link.MsgConn = s.msgTunnel
|
||||||
go s.linkProcess(link, c)
|
go linkProcess(link, c, s.tunnel)
|
||||||
link.Run(false)
|
link.RunWrite()
|
||||||
}
|
}
|
||||||
case common.RES_CLOSE:
|
case common.RES_CLOSE:
|
||||||
logs.Error("The authentication key is connected by another client or the server closes the client.")
|
logs.Error("The authentication key is connected by another client or the server closes the client.")
|
||||||
@ -91,6 +91,14 @@ func (s *TRPClient) processor(c *conn.Conn) {
|
|||||||
case common.RES_MSG:
|
case common.RES_MSG:
|
||||||
logs.Error("Server-side return error")
|
logs.Error("Server-side return error")
|
||||||
break
|
break
|
||||||
|
case common.NEW_UDP_CONN:
|
||||||
|
//读取服务端地址、密钥 继续做处理
|
||||||
|
if lAddr, err := c.GetLenContent(); err != nil {
|
||||||
|
return
|
||||||
|
} else if pwd, err := c.GetLenContent(); err == nil {
|
||||||
|
logs.Warn(string(lAddr), string(pwd))
|
||||||
|
go s.newUdpConn(string(lAddr), string(pwd))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
logs.Warn("The error could not be resolved")
|
logs.Warn("The error could not be resolved")
|
||||||
break
|
break
|
||||||
@ -100,37 +108,112 @@ func (s *TRPClient) processor(c *conn.Conn) {
|
|||||||
s.Close()
|
s.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TRPClient) linkProcess(link *conn.Link, c *conn.Conn) {
|
func (s *TRPClient) newUdpConn(rAddr string, md5Password string) {
|
||||||
|
tmpConn, err := net.Dial("udp", "114.114.114.114:53")
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tmpConn.Close()
|
||||||
|
//与服务端建立udp连接
|
||||||
|
localAddr, _ := net.ResolveUDPAddr("udp", tmpConn.LocalAddr().String())
|
||||||
|
localConn, err := net.ListenUDP("udp", localAddr)
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
localKcpConn, err := kcp.NewConn(rAddr, nil, 150, 3, localConn)
|
||||||
|
logs.Warn(localConn.RemoteAddr(), rAddr)
|
||||||
|
conn.SetUdpSession(localKcpConn)
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
localToolConn := conn.NewConn(localKcpConn)
|
||||||
|
//写入密钥、provider身份
|
||||||
|
if _, err := localToolConn.Write([]byte(md5Password)); err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := localToolConn.Write([]byte(common.WORK_P2P_PROVIDER)); err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//接收服务端传的visitor地址
|
||||||
|
if b, err := localToolConn.GetLenContent(); err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
logs.Warn("收到服务端回传地址", string(b))
|
||||||
|
//向visitor地址发送测试消息
|
||||||
|
visitorAddr, err := net.ResolveUDPAddr("udp", string(b))
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
logs.Warn(visitorAddr.String())
|
||||||
|
if n, err := localConn.WriteTo([]byte("test"), visitorAddr); err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
} else {
|
||||||
|
logs.Warn("write", n)
|
||||||
|
}
|
||||||
|
//给服务端发反馈
|
||||||
|
if _, err := localToolConn.Write([]byte(common.VERIFY_SUCCESS)); err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
//关闭与服务端的连接
|
||||||
|
localConn.Close()
|
||||||
|
//关闭与服务端udp conn,建立新的监听
|
||||||
|
localConn, err = net.ListenUDP("udp", localAddr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
l, err := kcp.ServeConn(nil, 150, 3, localConn)
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
//接收新的监听,得到conn,
|
||||||
|
udpTunnel, err := l.AcceptKCP()
|
||||||
|
logs.Warn(udpTunnel.RemoteAddr(), udpTunnel.LocalAddr())
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
l.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn.SetUdpSession(udpTunnel)
|
||||||
|
if udpTunnel.RemoteAddr().String() == string(b) {
|
||||||
|
//读取link,设置msgCh 设置msgConn消息回传响应机制
|
||||||
|
c, e := net.Dial("tcp", "123.206.77.88:22")
|
||||||
|
if e != nil {
|
||||||
|
logs.Warn(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go common.CopyBuffer(c, udpTunnel)
|
||||||
|
common.CopyBuffer(udpTunnel, c)
|
||||||
|
//读取flag ping/new/msg/msgConn//分别对于不同的做法
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkProcess(link *conn.Link, statusConn, msgConn *conn.Conn) {
|
||||||
link.Host = common.FormatAddress(link.Host)
|
link.Host = common.FormatAddress(link.Host)
|
||||||
//与目标建立连接
|
//与目标建立连接
|
||||||
server, err := net.DialTimeout(link.ConnType, link.Host, time.Second*3)
|
server, err := net.DialTimeout(link.ConnType, link.Host, time.Second*3)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.WriteFail(link.Id)
|
statusConn.WriteFail(link.Id)
|
||||||
logs.Warn("connect to ", link.Host, "error:", err)
|
logs.Warn("connect to ", link.Host, "error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.WriteSuccess(link.Id)
|
statusConn.WriteSuccess(link.Id)
|
||||||
link.Conn = conn.NewConn(server)
|
link.Conn = conn.NewConn(server)
|
||||||
buf := pool.BufPoolCopy.Get().([]byte)
|
link.RunRead(msgConn)
|
||||||
for {
|
|
||||||
if n, err := server.Read(buf); err != nil {
|
|
||||||
s.tunnel.SendMsg([]byte(common.IO_EOF), link)
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
if _, err := s.tunnel.SendMsg(buf[:n], link); err != nil {
|
|
||||||
c.Close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if link.ConnType == common.CONN_UDP {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<-link.StatusCh
|
|
||||||
}
|
|
||||||
pool.PutBufPoolCopy(buf)
|
|
||||||
s.Lock()
|
|
||||||
s.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TRPClient) getMsgStatus() {
|
func (s *TRPClient) getMsgStatus() {
|
||||||
|
@ -3,8 +3,10 @@ package client
|
|||||||
import (
|
import (
|
||||||
"github.com/cnlh/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"github.com/cnlh/nps/lib/config"
|
"github.com/cnlh/nps/lib/config"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
"github.com/cnlh/nps/lib/crypt"
|
"github.com/cnlh/nps/lib/crypt"
|
||||||
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -39,16 +41,81 @@ func StartLocalServer(l *config.LocalServer, config *config.CommonConfig) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func process(conn net.Conn, config *config.CommonConfig, l *config.LocalServer) {
|
func process(localTcpConn net.Conn, config *config.CommonConfig, l *config.LocalServer) {
|
||||||
c, err := NewConn(config.Tp, config.VKey, config.Server, common.WORD_SECRET, config.ProxyUrl)
|
var workType string
|
||||||
|
if l.Type == "secret" {
|
||||||
|
workType = common.WORK_SECRET
|
||||||
|
} else {
|
||||||
|
workType = common.WORK_P2P
|
||||||
|
}
|
||||||
|
remoteConn, err := NewConn(config.Tp, config.VKey, config.Server, workType, config.ProxyUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error("Local connection server failed ", err.Error())
|
logs.Error("Local connection server failed ", err.Error())
|
||||||
}
|
}
|
||||||
if _, err := c.Write([]byte(crypt.Md5(l.Password))); err != nil {
|
if _, err := remoteConn.Write([]byte(crypt.Md5(l.Password))); err != nil {
|
||||||
logs.Error("Local connection server failed ", err.Error())
|
logs.Error("Local connection server failed ", err.Error())
|
||||||
}
|
}
|
||||||
go common.CopyBuffer(c, conn)
|
if l.Type == "secret" {
|
||||||
common.CopyBuffer(conn, c)
|
go common.CopyBuffer(remoteConn, localTcpConn)
|
||||||
c.Close()
|
common.CopyBuffer(localTcpConn, remoteConn)
|
||||||
conn.Close()
|
remoteConn.Close()
|
||||||
|
localTcpConn.Close()
|
||||||
|
} else {
|
||||||
|
//读取服务端地址、密钥 继续做处理
|
||||||
|
logs.Warn(111)
|
||||||
|
if rAddr, err := remoteConn.GetLenContent(); err != nil {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
logs.Warn(222)
|
||||||
|
//与服务端udp建立连接
|
||||||
|
tmpConn, err := net.Dial("udp", "114.114.114.114:53")
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
tmpConn.Close()
|
||||||
|
//与服务端建立udp连接
|
||||||
|
localAddr, _ := net.ResolveUDPAddr("udp", tmpConn.LocalAddr().String())
|
||||||
|
localConn, err := net.ListenUDP("udp", localAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logs.Warn(333)
|
||||||
|
localKcpConn, err := kcp.NewConn(string(rAddr), nil, 150, 3, localConn)
|
||||||
|
conn.SetUdpSession(localKcpConn)
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
}
|
||||||
|
localToolConn := conn.NewConn(localKcpConn)
|
||||||
|
//写入密钥、provider身份
|
||||||
|
if _, err := localToolConn.Write([]byte(crypt.Md5(l.Password))); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := localToolConn.Write([]byte(common.WORK_P2P_VISITOR)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logs.Warn(444)
|
||||||
|
//接收服务端传的visitor地址
|
||||||
|
if b, err := localToolConn.GetLenContent(); err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
logs.Warn("收到服务回传地址", string(b))
|
||||||
|
//关闭与服务端连接
|
||||||
|
localConn.Close()
|
||||||
|
//建立新的连接
|
||||||
|
localConn, err = net.ListenUDP("udp", localAddr)
|
||||||
|
udpTunnel, err := kcp.NewConn(string(b), nil, 150, 3, localConn)
|
||||||
|
if err != nil || udpTunnel == nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn.SetUdpSession(udpTunnel)
|
||||||
|
logs.Warn(udpTunnel.RemoteAddr(), string(b), udpTunnel.LocalAddr())
|
||||||
|
|
||||||
|
go common.CopyBuffer(udpTunnel, localTcpConn)
|
||||||
|
common.CopyBuffer(localTcpConn, udpTunnel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[common]
|
[common]
|
||||||
server=127.0.0.1:8284
|
server=123.206.77.88:8284
|
||||||
tp=tcp
|
tp=tcp
|
||||||
vkey=123
|
vkey=123
|
||||||
auto_reconnection=true
|
auto_reconnection=true
|
||||||
@ -16,10 +16,6 @@ host_change=www.proxy.com
|
|||||||
target=127.0.0.1:8080
|
target=127.0.0.1:8080
|
||||||
location=/cdn
|
location=/cdn
|
||||||
|
|
||||||
[ssh_1118]
|
|
||||||
mode=secretServer
|
|
||||||
password=1111
|
|
||||||
target=123.206.77.88:22
|
|
||||||
|
|
||||||
[tcp]
|
[tcp]
|
||||||
mode=tcpServer
|
mode=tcpServer
|
||||||
@ -38,3 +34,7 @@ port=9004
|
|||||||
mode=udpServer
|
mode=udpServer
|
||||||
port=9003
|
port=9003
|
||||||
target=114.114.114.53
|
target=114.114.114.53
|
||||||
|
|
||||||
|
[p2p_ssh]
|
||||||
|
port=2000
|
||||||
|
password=p2pssh
|
@ -13,12 +13,16 @@ const (
|
|||||||
WORK_SEND_STATUS = "sdst"
|
WORK_SEND_STATUS = "sdst"
|
||||||
WORK_CONFIG = "conf"
|
WORK_CONFIG = "conf"
|
||||||
WORK_REGISTER = "rgst"
|
WORK_REGISTER = "rgst"
|
||||||
WORD_SECRET = "sert"
|
WORK_SECRET = "sert"
|
||||||
|
WORK_P2P = "p2pm"
|
||||||
|
WORK_P2P_VISITOR = "p2pv"
|
||||||
|
WORK_P2P_PROVIDER = "p2pp"
|
||||||
WORK_STATUS = "stus"
|
WORK_STATUS = "stus"
|
||||||
RES_SIGN = "sign"
|
RES_SIGN = "sign"
|
||||||
RES_MSG = "msg0"
|
RES_MSG = "msg0"
|
||||||
RES_CLOSE = "clse"
|
RES_CLOSE = "clse"
|
||||||
NEW_CONN = "conn" //新连接标志
|
NEW_CONN = "conn" //新连接标志
|
||||||
|
NEW_UDP_CONN = "udpc" //p2p udp conn
|
||||||
NEW_TASK = "task" //新连接标志
|
NEW_TASK = "task" //新连接标志
|
||||||
NEW_CONF = "conf" //新连接标志
|
NEW_CONF = "conf" //新连接标志
|
||||||
NEW_HOST = "host" //新连接标志
|
NEW_HOST = "host" //新连接标志
|
||||||
@ -33,4 +37,5 @@ WWW-Authenticate: Basic realm="easyProxy"
|
|||||||
ConnectionFailBytes = `HTTP/1.1 404 Not Found
|
ConnectionFailBytes = `HTTP/1.1 404 Not Found
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
)
|
)
|
||||||
|
@ -251,7 +251,29 @@ func GetIpByAddr(addr string) string {
|
|||||||
|
|
||||||
func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
|
func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
|
||||||
buf := pool.BufPoolCopy.Get().([]byte)
|
buf := pool.BufPoolCopy.Get().([]byte)
|
||||||
io.CopyBuffer(dst, src, buf)
|
for {
|
||||||
pool.PutBufPoolCopy(buf)
|
nr, er := src.Read(buf)
|
||||||
|
if nr > 0 {
|
||||||
|
nw, ew := dst.Write(buf[0:nr])
|
||||||
|
if nw > 0 {
|
||||||
|
written += int64(nw)
|
||||||
|
}
|
||||||
|
if ew != nil {
|
||||||
|
err = ew
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if nr != nw {
|
||||||
|
err = io.ErrShortWrite
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if er != nil {
|
||||||
|
if er != io.EOF {
|
||||||
|
err = er
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer pool.PutBufPoolCopy(buf)
|
||||||
return written, err
|
return written, err
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ type CommonConfig struct {
|
|||||||
Client *file.Client
|
Client *file.Client
|
||||||
}
|
}
|
||||||
type LocalServer struct {
|
type LocalServer struct {
|
||||||
|
Type string
|
||||||
Port int
|
Port int
|
||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
@ -53,7 +54,15 @@ func NewConfig(path string) (c *Config, err error) {
|
|||||||
nowContent = c.content[nowIndex:nextIndex]
|
nowContent = c.content[nowIndex:nextIndex]
|
||||||
|
|
||||||
if strings.Index(getTitleContent(c.title[i]), "secret") == 0 {
|
if strings.Index(getTitleContent(c.title[i]), "secret") == 0 {
|
||||||
c.LocalServer = append(c.LocalServer, delLocalService(nowContent))
|
local := delLocalService(nowContent)
|
||||||
|
local.Type = "secret"
|
||||||
|
c.LocalServer = append(c.LocalServer, local)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.Index(getTitleContent(c.title[i]), "p2p") == 0 {
|
||||||
|
local := delLocalService(nowContent)
|
||||||
|
local.Type = "p2p"
|
||||||
|
c.LocalServer = append(c.LocalServer, local)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch c.title[i] {
|
switch c.title[i] {
|
||||||
|
@ -69,6 +69,15 @@ func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http.
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Conn) GetLenContent() (b []byte, err error) {
|
||||||
|
var l int
|
||||||
|
if l, err = s.GetLen(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b, err = s.ReadLen(l)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//读取指定长度内容
|
//读取指定长度内容
|
||||||
func (s *Conn) ReadLen(cLen int) ([]byte, error) {
|
func (s *Conn) ReadLen(cLen int) ([]byte, error) {
|
||||||
if cLen > pool.PoolSize {
|
if cLen > pool.PoolSize {
|
||||||
@ -77,10 +86,11 @@ func (s *Conn) ReadLen(cLen int) ([]byte, error) {
|
|||||||
var buf []byte
|
var buf []byte
|
||||||
if cLen < pool.PoolSizeSmall {
|
if cLen < pool.PoolSizeSmall {
|
||||||
buf = pool.BufPoolSmall.Get().([]byte)[:cLen]
|
buf = pool.BufPoolSmall.Get().([]byte)[:cLen]
|
||||||
defer pool.PutBufPoolSmall(buf)
|
//TODO 回收
|
||||||
|
//defer pool.PutBufPoolSmall(buf)
|
||||||
} else {
|
} else {
|
||||||
buf = pool.BufPoolMax.Get().([]byte)[:cLen]
|
buf = pool.BufPoolMax.Get().([]byte)[:cLen]
|
||||||
defer pool.PutBufPoolMax(buf)
|
//defer pool.PutBufPoolMax(buf)
|
||||||
}
|
}
|
||||||
if n, err := io.ReadFull(s, buf); err != nil || n != cLen {
|
if n, err := io.ReadFull(s, buf); err != nil || n != cLen {
|
||||||
return buf, errors.New("Error reading specified length " + err.Error())
|
return buf, errors.New("Error reading specified length " + err.Error())
|
||||||
@ -95,6 +105,14 @@ func (s *Conn) GetLen() (int, error) {
|
|||||||
return int(l), err
|
return int(l), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Conn) WriteLenContent(buf []byte) (err error) {
|
||||||
|
var b []byte
|
||||||
|
if b, err = GetLenBytes(buf); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return binary.Write(s.Conn, binary.LittleEndian, b)
|
||||||
|
}
|
||||||
|
|
||||||
//read flag
|
//read flag
|
||||||
func (s *Conn) ReadFlag() (string, error) {
|
func (s *Conn) ReadFlag() (string, error) {
|
||||||
val, err := s.ReadLen(4)
|
val, err := s.ReadLen(4)
|
||||||
@ -477,7 +495,6 @@ func (s *Conn) WriteChan() (int, error) {
|
|||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
return s.Write([]byte(common.WORK_CHAN))
|
return s.Write([]byte(common.WORK_CHAN))
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取长度+内容
|
//获取长度+内容
|
||||||
func GetLenBytes(buf []byte) (b []byte, err error) {
|
func GetLenBytes(buf []byte) (b []byte, err error) {
|
||||||
raw := bytes.NewBuffer([]byte{})
|
raw := bytes.NewBuffer([]byte{})
|
||||||
@ -491,6 +508,7 @@ func GetLenBytes(buf []byte) (b []byte, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//解析出长度
|
//解析出长度
|
||||||
func GetLenByBytes(buf []byte) (int, error) {
|
func GetLenByBytes(buf []byte) (int, error) {
|
||||||
nlen := binary.LittleEndian.Uint32(buf)
|
nlen := binary.LittleEndian.Uint32(buf)
|
||||||
@ -508,4 +526,5 @@ func SetUdpSession(sess *kcp.UDPSession) {
|
|||||||
sess.SetNoDelay(1, 10, 2, 1)
|
sess.SetNoDelay(1, 10, 2, 1)
|
||||||
sess.SetMtu(1600)
|
sess.SetMtu(1600)
|
||||||
sess.SetACKNoDelay(true)
|
sess.SetACKNoDelay(true)
|
||||||
|
sess.SetWriteDelay(false)
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func NewLink(id int, connType string, host string, en, de int, crypt bool, c *Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Link) Run(flow bool) {
|
func (s *Link) RunWrite() {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -76,7 +76,7 @@ func (s *Link) Run(flow bool) {
|
|||||||
} else {
|
} else {
|
||||||
s.Conn.Write(content)
|
s.Conn.Write(content)
|
||||||
}
|
}
|
||||||
if flow {
|
if s.Flow != nil {
|
||||||
s.Flow.Add(0, len(content))
|
s.Flow.Add(0, len(content))
|
||||||
}
|
}
|
||||||
if s.ConnType == common.CONN_UDP {
|
if s.ConnType == common.CONN_UDP {
|
||||||
@ -89,3 +89,25 @@ func (s *Link) Run(flow bool) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
func (s *Link) RunRead(msgConn *Conn) {
|
||||||
|
buf := pool.BufPoolCopy.Get().([]byte)
|
||||||
|
for {
|
||||||
|
if n, err := s.Conn.Read(buf); err != nil {
|
||||||
|
msgConn.SendMsg([]byte(common.IO_EOF), s)
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
if _, err := msgConn.SendMsg(buf[:n], s); err != nil {
|
||||||
|
msgConn.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if s.ConnType == common.CONN_UDP {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if s.Flow != nil {
|
||||||
|
s.Flow.Add(n, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<-s.StatusCh
|
||||||
|
}
|
||||||
|
pool.PutBufPoolCopy(buf)
|
||||||
|
}
|
||||||
|
@ -181,7 +181,7 @@ func (s *Csv) DelTask(id int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//md5 password
|
//md5 password
|
||||||
func (s *Csv) GetSecretTask(p string) *Tunnel {
|
func (s *Csv) GetTaskByMd5Password(p string) *Tunnel {
|
||||||
for _, v := range s.Tasks {
|
for _, v := range s.Tasks {
|
||||||
if crypt.Md5(v.Password) == p {
|
if crypt.Md5(v.Password) == p {
|
||||||
return v
|
return v
|
||||||
|
@ -53,7 +53,6 @@ func NewClient(vKey string, noStore bool, noDisplay bool) *Client {
|
|||||||
Flow: new(Flow),
|
Flow: new(Flow),
|
||||||
Rate: nil,
|
Rate: nil,
|
||||||
NoStore: noStore,
|
NoStore: noStore,
|
||||||
id: GetCsvDb().GetClientId(),
|
|
||||||
RWMutex: sync.RWMutex{},
|
RWMutex: sync.RWMutex{},
|
||||||
NoDisplay: noDisplay,
|
NoDisplay: noDisplay,
|
||||||
}
|
}
|
||||||
|
32
lib/mux/bytes.go
Normal file
32
lib/mux/bytes.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
//write bytes with int32 length
|
||||||
|
func WriteLenBytes(buf []byte, w io.Writer) (int, error) {
|
||||||
|
raw := bytes.NewBuffer([]byte{})
|
||||||
|
if err := binary.Write(raw, binary.LittleEndian, int32(len(buf))); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if err := binary.Write(raw, binary.LittleEndian, buf); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return w.Write(raw.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
//read bytes by length
|
||||||
|
func ReadLenBytes(buf []byte, r io.Reader) (int, error) {
|
||||||
|
var l int32
|
||||||
|
var err error
|
||||||
|
if binary.Read(r, binary.LittleEndian, &l) != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if _, err = io.ReadFull(r, buf[:l]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(l), nil
|
||||||
|
}
|
148
lib/mux/conn.go
Normal file
148
lib/mux/conn.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/cnlh/nps/lib/pool"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type conn struct {
|
||||||
|
net.Conn
|
||||||
|
readMsgCh chan []byte
|
||||||
|
getStatusCh chan struct{}
|
||||||
|
connStatusOkCh chan struct{}
|
||||||
|
connStatusFailCh chan struct{}
|
||||||
|
readTimeOut time.Time
|
||||||
|
writeTimeOut time.Time
|
||||||
|
sendMsgCh chan *msg //mux
|
||||||
|
sendStatusCh chan int32 //mux
|
||||||
|
connId int32
|
||||||
|
isClose bool
|
||||||
|
mux *Mux
|
||||||
|
}
|
||||||
|
|
||||||
|
type msg struct {
|
||||||
|
connId int32
|
||||||
|
content []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMsg(connId int32, content []byte) *msg {
|
||||||
|
return &msg{
|
||||||
|
connId: connId,
|
||||||
|
content: content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConn(connId int32, mux *Mux, sendMsgCh chan *msg, sendStatusCh chan int32) *conn {
|
||||||
|
return &conn{
|
||||||
|
readMsgCh: make(chan []byte),
|
||||||
|
getStatusCh: make(chan struct{}),
|
||||||
|
connStatusOkCh: make(chan struct{}),
|
||||||
|
connStatusFailCh: make(chan struct{}),
|
||||||
|
readTimeOut: time.Time{},
|
||||||
|
writeTimeOut: time.Time{},
|
||||||
|
sendMsgCh: sendMsgCh,
|
||||||
|
sendStatusCh: sendStatusCh,
|
||||||
|
connId: connId,
|
||||||
|
isClose: false,
|
||||||
|
mux: mux,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) Read(buf []byte) (int, error) {
|
||||||
|
if s.isClose {
|
||||||
|
return 0, errors.New("the conn has closed")
|
||||||
|
}
|
||||||
|
var b []byte
|
||||||
|
if t := s.readTimeOut.Sub(time.Now()); t > 0 {
|
||||||
|
timer := time.NewTimer(t)
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
s.Close()
|
||||||
|
return 0, errors.New("read timeout")
|
||||||
|
case b = <-s.readMsgCh:
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
b = <-s.readMsgCh
|
||||||
|
}
|
||||||
|
defer pool.PutBufPoolCopy(b)
|
||||||
|
if s.isClose {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
s.sendStatusCh <- s.connId
|
||||||
|
return copy(buf, b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) Write(buf []byte) (int, error) {
|
||||||
|
if s.isClose {
|
||||||
|
return 0, errors.New("the conn has closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t := s.writeTimeOut.Sub(time.Now()); t > 0 {
|
||||||
|
timer := time.NewTimer(t)
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
s.Close()
|
||||||
|
return 0, errors.New("write timeout")
|
||||||
|
case s.sendMsgCh <- NewMsg(s.connId, buf):
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.sendMsgCh <- NewMsg(s.connId, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t := s.writeTimeOut.Sub(time.Now()); t > 0 {
|
||||||
|
timer := time.NewTimer(t)
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
s.Close()
|
||||||
|
return 0, errors.New("write timeout")
|
||||||
|
case <-s.getStatusCh:
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
<-s.getStatusCh
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.isClose {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
return len(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) Close() error {
|
||||||
|
if s.isClose {
|
||||||
|
return errors.New("the conn has closed")
|
||||||
|
}
|
||||||
|
s.isClose = true
|
||||||
|
close(s.getStatusCh)
|
||||||
|
close(s.readMsgCh)
|
||||||
|
close(s.connStatusOkCh)
|
||||||
|
close(s.connStatusFailCh)
|
||||||
|
s.sendMsgCh <- NewMsg(s.connId, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) LocalAddr() net.Addr {
|
||||||
|
return s.mux.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) RemoteAddr() net.Addr {
|
||||||
|
return s.mux.conn.RemoteAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) SetDeadline(t time.Time) error {
|
||||||
|
s.readTimeOut = t
|
||||||
|
s.writeTimeOut = t
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) SetReadDeadline(t time.Time) error {
|
||||||
|
s.readTimeOut = t
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *conn) SetWriteDeadline(t time.Time) error {
|
||||||
|
s.writeTimeOut = t
|
||||||
|
return nil
|
||||||
|
}
|
64
lib/mux/map.go
Normal file
64
lib/mux/map.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type connMap struct {
|
||||||
|
connMap map[int32]*conn
|
||||||
|
closeCh chan struct{}
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConnMap() *connMap {
|
||||||
|
connMap := &connMap{
|
||||||
|
connMap: make(map[int32]*conn),
|
||||||
|
closeCh: make(chan struct{}),
|
||||||
|
}
|
||||||
|
go connMap.clean()
|
||||||
|
return connMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) Get(id int32) (*conn, bool) {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
if v, ok := s.connMap[id]; ok {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) Set(id int32, v *conn) {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
s.connMap[id] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) Close() {
|
||||||
|
s.Lock()
|
||||||
|
defer s.Unlock()
|
||||||
|
for _, v := range s.connMap {
|
||||||
|
v.isClose = true
|
||||||
|
}
|
||||||
|
s.closeCh <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *connMap) clean() {
|
||||||
|
ticker := time.NewTimer(time.Minute * 1)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
s.Lock()
|
||||||
|
for _, v := range s.connMap {
|
||||||
|
if v.isClose {
|
||||||
|
delete(s.connMap, v.connId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.Unlock()
|
||||||
|
case <-s.closeCh:
|
||||||
|
ticker.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
226
lib/mux/mux.go
Normal file
226
lib/mux/mux.go
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"github.com/cnlh/nps/lib/pool"
|
||||||
|
"math"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MUX_PING_FLAG int32 = iota
|
||||||
|
MUX_NEW_CONN_OK
|
||||||
|
MUX_NEW_CONN_Fail
|
||||||
|
MUX_NEW_MSG
|
||||||
|
MUX_MSG_SEND_OK
|
||||||
|
MUX_NEW_CONN
|
||||||
|
MUX_PING
|
||||||
|
MUX_CONN_CLOSE
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mux struct {
|
||||||
|
net.Listener
|
||||||
|
conn net.Conn
|
||||||
|
connMap *connMap
|
||||||
|
sendMsgCh chan *msg //write msg chan
|
||||||
|
sendStatusCh chan int32 //write read ok chan
|
||||||
|
newConnCh chan *conn
|
||||||
|
id int32
|
||||||
|
closeChan chan struct{}
|
||||||
|
isClose bool
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMux(c net.Conn) *Mux {
|
||||||
|
m := &Mux{
|
||||||
|
conn: c,
|
||||||
|
connMap: NewConnMap(),
|
||||||
|
sendMsgCh: make(chan *msg),
|
||||||
|
sendStatusCh: make(chan int32),
|
||||||
|
id: 0,
|
||||||
|
closeChan: make(chan struct{}),
|
||||||
|
newConnCh: make(chan *conn),
|
||||||
|
isClose: false,
|
||||||
|
}
|
||||||
|
//read session by flag
|
||||||
|
go m.readSession()
|
||||||
|
//write session
|
||||||
|
go m.writeSession()
|
||||||
|
//ping
|
||||||
|
go m.ping()
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) NewConn() (*conn, error) {
|
||||||
|
if s.isClose {
|
||||||
|
return nil, errors.New("the mux has closed")
|
||||||
|
}
|
||||||
|
conn := NewConn(s.getId(), s, s.sendMsgCh, s.sendStatusCh)
|
||||||
|
raw := bytes.NewBuffer([]byte{})
|
||||||
|
if err := binary.Write(raw, binary.LittleEndian, MUX_NEW_CONN); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := binary.Write(raw, binary.LittleEndian, conn.connId); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//it must be set before send
|
||||||
|
s.connMap.Set(conn.connId, conn)
|
||||||
|
if _, err := s.conn.Write(raw.Bytes()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-conn.connStatusOkCh:
|
||||||
|
return conn, nil
|
||||||
|
case <-conn.connStatusFailCh:
|
||||||
|
}
|
||||||
|
return nil, errors.New("create connection fail,the server refused the connection")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) Accept() (net.Conn, error) {
|
||||||
|
if s.isClose {
|
||||||
|
return nil, errors.New("accpet error,the conn has closed")
|
||||||
|
}
|
||||||
|
return <-s.newConnCh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) Addr() net.Addr {
|
||||||
|
return s.conn.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) ping() {
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(time.Second * 5)
|
||||||
|
raw := bytes.NewBuffer([]byte{})
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
}
|
||||||
|
//Avoid going beyond the scope
|
||||||
|
if (math.MaxInt32 - s.id) < 10000 {
|
||||||
|
s.id = 0
|
||||||
|
}
|
||||||
|
raw.Reset()
|
||||||
|
binary.Write(raw, binary.LittleEndian, MUX_PING_FLAG)
|
||||||
|
binary.Write(raw, binary.LittleEndian, MUX_PING)
|
||||||
|
if _, err := s.conn.Write(raw.Bytes()); err != nil {
|
||||||
|
s.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-s.closeChan:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) writeSession() {
|
||||||
|
go func() {
|
||||||
|
raw := bytes.NewBuffer([]byte{})
|
||||||
|
for {
|
||||||
|
raw.Reset()
|
||||||
|
select {
|
||||||
|
case msg := <-s.sendMsgCh:
|
||||||
|
if msg.content == nil { //close
|
||||||
|
binary.Write(raw, binary.LittleEndian, MUX_CONN_CLOSE)
|
||||||
|
binary.Write(raw, binary.LittleEndian, msg.connId)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
binary.Write(raw, binary.LittleEndian, MUX_NEW_MSG)
|
||||||
|
binary.Write(raw, binary.LittleEndian, msg.connId)
|
||||||
|
binary.Write(raw, binary.LittleEndian, int32(len(msg.content)))
|
||||||
|
binary.Write(raw, binary.LittleEndian, msg.content)
|
||||||
|
case connId := <-s.sendStatusCh:
|
||||||
|
binary.Write(raw, binary.LittleEndian, MUX_MSG_SEND_OK)
|
||||||
|
binary.Write(raw, binary.LittleEndian, connId)
|
||||||
|
}
|
||||||
|
if _, err := s.conn.Write(raw.Bytes()); err != nil {
|
||||||
|
s.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-s.closeChan:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) readSession() {
|
||||||
|
go func() {
|
||||||
|
raw := bytes.NewBuffer([]byte{})
|
||||||
|
for {
|
||||||
|
var flag, i int32
|
||||||
|
if binary.Read(s.conn, binary.LittleEndian, &flag) == nil {
|
||||||
|
if binary.Read(s.conn, binary.LittleEndian, &i) != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch flag {
|
||||||
|
case MUX_NEW_CONN: //new conn
|
||||||
|
conn := NewConn(i, s, s.sendMsgCh, s.sendStatusCh)
|
||||||
|
s.connMap.Set(i, conn) //it has been set before send ok
|
||||||
|
s.newConnCh <- conn
|
||||||
|
raw.Reset()
|
||||||
|
binary.Write(raw, binary.LittleEndian, MUX_NEW_CONN_OK)
|
||||||
|
binary.Write(raw, binary.LittleEndian, i)
|
||||||
|
s.conn.Write(raw.Bytes())
|
||||||
|
continue
|
||||||
|
case MUX_PING_FLAG: //ping
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if conn, ok := s.connMap.Get(i); ok {
|
||||||
|
switch flag {
|
||||||
|
case MUX_NEW_MSG: //new msg from remote conn
|
||||||
|
buf := pool.BufPoolCopy.Get().([]byte)
|
||||||
|
if n, err := ReadLenBytes(buf, s.conn); err == nil {
|
||||||
|
if !conn.isClose {
|
||||||
|
conn.readMsgCh <- buf[:n]
|
||||||
|
} else {
|
||||||
|
pool.PutBufPoolCopy(buf)
|
||||||
|
}
|
||||||
|
} else { //read len bytes error,the mux has broken
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case MUX_MSG_SEND_OK: //the remote has read
|
||||||
|
conn.getStatusCh <- struct{}{}
|
||||||
|
case MUX_NEW_CONN_OK: //conn ok
|
||||||
|
conn.connStatusOkCh <- struct{}{}
|
||||||
|
case MUX_NEW_CONN_Fail:
|
||||||
|
conn.connStatusFailCh <- struct{}{}
|
||||||
|
case MUX_CONN_CLOSE: //close the connection
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.Close()
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-s.closeChan:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Mux) Close() error {
|
||||||
|
if s.isClose {
|
||||||
|
return errors.New("the mux has closed")
|
||||||
|
}
|
||||||
|
s.isClose = true
|
||||||
|
s.connMap.Close()
|
||||||
|
s.closeChan <- struct{}{}
|
||||||
|
s.closeChan <- struct{}{}
|
||||||
|
s.closeChan <- struct{}{}
|
||||||
|
close(s.closeChan)
|
||||||
|
close(s.sendMsgCh)
|
||||||
|
close(s.sendStatusCh)
|
||||||
|
return s.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
//get new connId as unique flag
|
||||||
|
func (s *Mux) getId() int32 {
|
||||||
|
return atomic.AddInt32(&s.id, 1)
|
||||||
|
}
|
96
lib/mux/mux_test.go
Normal file
96
lib/mux/mux_test.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package mux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
_ "net/http/pprof"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var conn1 net.Conn
|
||||||
|
var conn2 net.Conn
|
||||||
|
|
||||||
|
func TestNewMux(t *testing.T) {
|
||||||
|
go func() {
|
||||||
|
http.ListenAndServe("0.0.0.0:8899", nil)
|
||||||
|
}()
|
||||||
|
logs.EnableFuncCallDepth(true)
|
||||||
|
logs.SetLogFuncCallDepth(3)
|
||||||
|
server()
|
||||||
|
client()
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
go func() {
|
||||||
|
m2 := NewMux(conn2)
|
||||||
|
for {
|
||||||
|
c, err := m2.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
go func(c net.Conn) {
|
||||||
|
c2, err := net.Dial("tcp", "127.0.0.1:8080")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
go common.CopyBuffer(c2, c)
|
||||||
|
common.CopyBuffer(c, c2)
|
||||||
|
c.Close()
|
||||||
|
c2.Close()
|
||||||
|
}(c)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
m1 := NewMux(conn1)
|
||||||
|
l, err := net.Listen("tcp", "127.0.0.1:7777")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
conn, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
go func(conn net.Conn) {
|
||||||
|
tmpCpnn, err := m1.NewConn()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
go common.CopyBuffer(tmpCpnn, conn)
|
||||||
|
common.CopyBuffer(conn, tmpCpnn)
|
||||||
|
conn.Close()
|
||||||
|
tmpCpnn.Close()
|
||||||
|
}(conn)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func server() {
|
||||||
|
var err error
|
||||||
|
l, err := net.Listen("tcp", "127.0.0.1:9999")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
conn1, err = l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func client() {
|
||||||
|
var err error
|
||||||
|
conn2, err = net.Dial("tcp", "127.0.0.1:9999")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,7 @@ func PutBufPoolUdp(buf []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func PutBufPoolCopy(buf []byte) {
|
func PutBufPoolCopy(buf []byte) {
|
||||||
if cap(buf) == PoolSizeCopy {
|
if cap(buf) == PoolSizeCopy {
|
||||||
BufPoolCopy.Put(buf[:PoolSizeCopy])
|
BufPoolCopy.Put(buf[:PoolSizeCopy])
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/cnlh/nps/lib/common"
|
"github.com/cnlh/nps/lib/common"
|
||||||
"github.com/cnlh/nps/lib/conn"
|
"github.com/cnlh/nps/lib/conn"
|
||||||
"github.com/cnlh/nps/lib/file"
|
"github.com/cnlh/nps/lib/file"
|
||||||
"github.com/cnlh/nps/lib/pool"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
@ -58,27 +57,11 @@ func (s *BaseServer) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *
|
|||||||
flow.Add(len(rb), 0)
|
flow.Add(len(rb), 0)
|
||||||
<-link.StatusCh
|
<-link.StatusCh
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := pool.BufPoolCopy.Get().([]byte)
|
|
||||||
for {
|
|
||||||
if err := s.checkFlow(); err != nil {
|
if err := s.checkFlow(); err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
break
|
|
||||||
}
|
|
||||||
if n, err := c.Read(buf); err != nil {
|
|
||||||
tunnel.SendMsg([]byte(common.IO_EOF), link)
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
if _, err := tunnel.SendMsg(buf[:n], link); err != nil {
|
|
||||||
c.Close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
flow.Add(n, 0)
|
|
||||||
}
|
|
||||||
<-link.StatusCh
|
|
||||||
}
|
}
|
||||||
|
link.RunRead(tunnel)
|
||||||
s.task.Client.AddConn()
|
s.task.Client.AddConn()
|
||||||
pool.PutBufPoolCopy(buf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseServer) writeConnFail(c net.Conn) {
|
func (s *BaseServer) writeConnFail(c net.Conn) {
|
||||||
@ -111,7 +94,7 @@ func (s *BaseServer) DealClient(c *conn.Conn, addr string, rb []byte) error {
|
|||||||
c.Close()
|
c.Close()
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
link.Run(true)
|
link.RunWrite()
|
||||||
s.linkCopy(link, c, rb, tunnel, s.task.Flow)
|
s.linkCopy(link, c, rb, tunnel, s.task.Flow)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -150,7 +150,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) {
|
|||||||
logs.Notice(err)
|
logs.Notice(err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
lk.Run(true)
|
lk.RunWrite()
|
||||||
isConn = false
|
isConn = false
|
||||||
} else {
|
} else {
|
||||||
r, err = http.ReadRequest(bufio.NewReader(c))
|
r, err = http.ReadRequest(bufio.NewReader(c))
|
||||||
|
104
server/proxy/p2p.go
Normal file
104
server/proxy/p2p.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cnlh/nps/lib/common"
|
||||||
|
"github.com/cnlh/nps/lib/conn"
|
||||||
|
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
|
||||||
|
"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type P2PServer struct {
|
||||||
|
BaseServer
|
||||||
|
p2pPort int
|
||||||
|
p2p map[string]*p2p
|
||||||
|
}
|
||||||
|
|
||||||
|
type p2p struct {
|
||||||
|
provider *conn.Conn
|
||||||
|
visitor *conn.Conn
|
||||||
|
visitorAddr string
|
||||||
|
providerAddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewP2PServer(p2pPort int) *P2PServer {
|
||||||
|
return &P2PServer{
|
||||||
|
p2pPort: p2pPort,
|
||||||
|
p2p: make(map[string]*p2p),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *P2PServer) Start() error {
|
||||||
|
kcpListener, err := kcp.ListenWithOptions(":"+strconv.Itoa(s.p2pPort), nil, 150, 3)
|
||||||
|
if err != nil {
|
||||||
|
logs.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
c, err := kcpListener.AcceptKCP()
|
||||||
|
conn.SetUdpSession(c)
|
||||||
|
if err != nil {
|
||||||
|
logs.Warn(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go s.p2pProcess(conn.NewConn(c))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *P2PServer) p2pProcess(c *conn.Conn) {
|
||||||
|
logs.Warn("new link", c.Conn.RemoteAddr())
|
||||||
|
//获取密钥
|
||||||
|
var (
|
||||||
|
f string
|
||||||
|
b []byte
|
||||||
|
err error
|
||||||
|
v *p2p
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
if b, err = c.ReadLen(32); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//获取角色
|
||||||
|
if f, err = c.ReadFlag(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logs.Warn("收到", string(b), f)
|
||||||
|
if v, ok = s.p2p[string(b)]; !ok {
|
||||||
|
v = new(p2p)
|
||||||
|
s.p2p[string(b)] = v
|
||||||
|
}
|
||||||
|
logs.Warn(f, c.Conn.RemoteAddr().String())
|
||||||
|
//存储
|
||||||
|
if f == common.WORK_P2P_VISITOR {
|
||||||
|
v.visitorAddr = c.Conn.RemoteAddr().String()
|
||||||
|
v.visitor = c
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
if v.provider != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logs.Warn("等待确认")
|
||||||
|
if _, err := v.provider.ReadFlag(); err == nil {
|
||||||
|
v.visitor.WriteLenContent([]byte(v.providerAddr))
|
||||||
|
logs.Warn("收到确认")
|
||||||
|
delete(s.p2p, string(b))
|
||||||
|
} else {
|
||||||
|
logs.Warn("收到确认失败", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v.providerAddr = c.Conn.RemoteAddr().String()
|
||||||
|
v.provider = c
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
if v.visitor != nil {
|
||||||
|
v.provider.WriteLenContent([]byte(v.visitorAddr))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//假设是连接者、等待对应的被连接者连上后,发送被连接者信息
|
||||||
|
//假设是被连接者,等待对应的连接者脸上后,发送连接者信息
|
||||||
|
}
|
@ -148,7 +148,7 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) {
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
s.sendReply(c, succeeded)
|
s.sendReply(c, succeeded)
|
||||||
link.Run(true)
|
link.RunWrite()
|
||||||
s.linkCopy(link, conn.NewConn(c), nil, tunnel, s.task.Flow)
|
s.linkCopy(link, conn.NewConn(c), nil, tunnel, s.task.Flow)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -58,7 +58,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
|||||||
s.task.Flow.Add(len(data), 0)
|
s.task.Flow.Add(len(data), 0)
|
||||||
tunnel.SendMsg(data, link)
|
tunnel.SendMsg(data, link)
|
||||||
pool.PutBufPoolUdp(data)
|
pool.PutBufPoolUdp(data)
|
||||||
link.Run(true)
|
link.RunWrite()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ func DealBridgeTask() {
|
|||||||
file.GetCsvDb().DelClient(id)
|
file.GetCsvDb().DelClient(id)
|
||||||
case s := <-Bridge.SecretChan:
|
case s := <-Bridge.SecretChan:
|
||||||
logs.Trace("New secret connection, addr", s.Conn.Conn.RemoteAddr())
|
logs.Trace("New secret connection, addr", s.Conn.Conn.RemoteAddr())
|
||||||
if t := file.GetCsvDb().GetSecretTask(s.Password); t != nil {
|
if t := file.GetCsvDb().GetTaskByMd5Password(s.Password); t != nil {
|
||||||
if !t.Client.GetConn() {
|
if !t.Client.GetConn() {
|
||||||
logs.Info("Connections exceed the current client %d limit", t.Client.Id)
|
logs.Info("Connections exceed the current client %d limit", t.Client.Id)
|
||||||
s.Conn.Close()
|
s.Conn.Close()
|
||||||
@ -75,6 +75,9 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
|
|||||||
} else {
|
} else {
|
||||||
logs.Info("Server startup, the bridge type is %s, the bridge port is %d", bridgeType, bridgePort)
|
logs.Info("Server startup, the bridge type is %s, the bridge port is %d", bridgeType, bridgePort)
|
||||||
}
|
}
|
||||||
|
if p, err := beego.AppConfig.Int("p2pPort"); err == nil {
|
||||||
|
go proxy.NewP2PServer(p).Start()
|
||||||
|
}
|
||||||
go DealBridgeTask()
|
go DealBridgeTask()
|
||||||
if svr := NewMode(Bridge, cnf); svr != nil {
|
if svr := NewMode(Bridge, cnf); svr != nil {
|
||||||
if err := svr.Start(); err != nil {
|
if err := svr.Start(); err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user