mirror of
https://gitee.com/IrisVega/frp.git
synced 2024-11-01 22:31:29 +08:00
commit
edb97abf50
@ -3,15 +3,23 @@ export GO15VENDOREXPERIMENT := 1
|
|||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
build: gox app more
|
build: app
|
||||||
|
|
||||||
gox:
|
|
||||||
go get github.com/mitchellh/gox
|
|
||||||
|
|
||||||
app:
|
app:
|
||||||
gox -osarch "darwin/386 darwin/amd64 linux/386 linux/amd64 linux/arm windows/386 windows/amd64" ./src/...
|
env GOOS=darwin GOARCH=386 go build -o ./frpc_darwin_386 ./src/cmd/frpc
|
||||||
|
env GOOS=darwin GOARCH=386 go build -o ./frps_darwin_386 ./src/cmd/frps
|
||||||
more:
|
env GOOS=darwin GOARCH=amd64 go build -o ./frpc_darwin_amd64 ./src/cmd/frpc
|
||||||
|
env GOOS=darwin GOARCH=amd64 go build -o ./frps_darwin_amd64 ./src/cmd/frps
|
||||||
|
env GOOS=linux GOARCH=386 go build -o ./frpc_linux_386 ./src/cmd/frpc
|
||||||
|
env GOOS=linux GOARCH=386 go build -o ./frps_linux_386 ./src/cmd/frps
|
||||||
|
env GOOS=linux GOARCH=amd64 go build -o ./frpc_linux_amd64 ./src/cmd/frpc
|
||||||
|
env GOOS=linux GOARCH=amd64 go build -o ./frps_linux_amd64 ./src/cmd/frps
|
||||||
|
env GOOS=linux GOARCH=arm go build -o ./frpc_linux_arm ./src/cmd/frpc
|
||||||
|
env GOOS=linux GOARCH=arm go build -o ./frps_linux_arm ./src/cmd/frps
|
||||||
|
env GOOS=windows GOARCH=386 go build -o ./frpc_windows_386.exe ./src/cmd/frpc
|
||||||
|
env GOOS=windows GOARCH=386 go build -o ./frps_windows_386.exe ./src/cmd/frps
|
||||||
|
env GOOS=windows GOARCH=amd64 go build -o ./frpc_windows_amd64.exe ./src/cmd/frpc
|
||||||
|
env GOOS=windows GOARCH=amd64 go build -o ./frps_windows_amd64.exe ./src/cmd/frps
|
||||||
env GOOS=linux GOARCH=mips64 go build -o ./frpc_linux_mips64 ./src/cmd/frpc
|
env GOOS=linux GOARCH=mips64 go build -o ./frpc_linux_mips64 ./src/cmd/frpc
|
||||||
env GOOS=linux GOARCH=mips64 go build -o ./frps_linux_mips64 ./src/cmd/frps
|
env GOOS=linux GOARCH=mips64 go build -o ./frps_linux_mips64 ./src/cmd/frps
|
||||||
env GOOS=linux GOARCH=mips64le go build -o ./frpc_linux_mips64le ./src/cmd/frpc
|
env GOOS=linux GOARCH=mips64le go build -o ./frpc_linux_mips64le ./src/cmd/frpc
|
||||||
|
@ -219,7 +219,7 @@ Then visit `http://[server_addr]:7500` to see dashboard, default username and pa
|
|||||||
|
|
||||||
Client that want's to register must set a global `auth_token` equals to frps.ini.
|
Client that want's to register must set a global `auth_token` equals to frps.ini.
|
||||||
|
|
||||||
Note that time duration bewtween frpc and frps mustn't exceed 15 minutes because timestamp is used for authentication.
|
Note that time duration between frpc and frps mustn't exceed 15 minutes because timestamp is used for authentication.
|
||||||
|
|
||||||
Howerver, this timeout duration can be modified by setting `authentication_timeout` in frps's configure file. It's defalut value is 900, means 15 minutes. If it is equals 0, then frps will not check authentication timeout.
|
Howerver, this timeout duration can be modified by setting `authentication_timeout` in frps's configure file. It's defalut value is 900, means 15 minutes. If it is equals 0, then frps will not check authentication timeout.
|
||||||
|
|
||||||
@ -452,7 +452,6 @@ http_proxy = http://user:pwd@192.168.1.128:8080
|
|||||||
|
|
||||||
## Development Plan
|
## Development Plan
|
||||||
|
|
||||||
* Url router.
|
|
||||||
* Log http request information in frps.
|
* Log http request information in frps.
|
||||||
* Direct reverse proxy, like haproxy.
|
* Direct reverse proxy, like haproxy.
|
||||||
* Load balance to different service in frpc.
|
* Load balance to different service in frpc.
|
||||||
@ -497,3 +496,4 @@ Donate money by [paypal](https://www.paypal.me/fatedier) to my account **fatedie
|
|||||||
* [Damon Zhao](https://github.com/se77en)
|
* [Damon Zhao](https://github.com/se77en)
|
||||||
* [Manfred Touron](https://github.com/moul)
|
* [Manfred Touron](https://github.com/moul)
|
||||||
* [xuebing1110](https://github.com/xuebing1110)
|
* [xuebing1110](https://github.com/xuebing1110)
|
||||||
|
* [Anbitioner](https://github.com/bingtianbaihua)
|
||||||
|
@ -469,7 +469,6 @@ http_proxy = http://user:pwd@192.168.1.128:8080
|
|||||||
|
|
||||||
计划在后续版本中加入的功能与优化,排名不分先后,如果有其他功能建议欢迎在 [issues](https://github.com/fatedier/frp/issues) 中反馈。
|
计划在后续版本中加入的功能与优化,排名不分先后,如果有其他功能建议欢迎在 [issues](https://github.com/fatedier/frp/issues) 中反馈。
|
||||||
|
|
||||||
* 支持 url 路由转发。
|
|
||||||
* frps 记录 http 请求日志。
|
* frps 记录 http 请求日志。
|
||||||
* frps 支持直接反向代理,类似 haproxy。
|
* frps 支持直接反向代理,类似 haproxy。
|
||||||
* frpc 支持负载均衡到后端不同服务。
|
* frpc 支持负载均衡到后端不同服务。
|
||||||
@ -516,3 +515,4 @@ frp 交流群:606194980 (QQ 群号)
|
|||||||
* [Damon Zhao](https://github.com/se77en)
|
* [Damon Zhao](https://github.com/se77en)
|
||||||
* [Manfred Touron](https://github.com/moul)
|
* [Manfred Touron](https://github.com/moul)
|
||||||
* [xuebing1110](https://github.com/xuebing1110)
|
* [xuebing1110](https://github.com/xuebing1110)
|
||||||
|
* [Anbitioner](https://github.com/bingtianbaihua)
|
||||||
|
@ -22,6 +22,10 @@ auth_token = 123
|
|||||||
# for privilege mode
|
# for privilege mode
|
||||||
privilege_token = 12345678
|
privilege_token = 12345678
|
||||||
|
|
||||||
|
# heartbeat configure, it's not recommended to modify the default value
|
||||||
|
# the default value of heartbeat_interval is 10 and heartbeat_timeout is 30
|
||||||
|
# heartbeat_interval = 10
|
||||||
|
# heartbeat_timeout = 30
|
||||||
|
|
||||||
# ssh is the proxy name same as server's configuration
|
# ssh is the proxy name same as server's configuration
|
||||||
[ssh]
|
[ssh]
|
||||||
|
@ -30,6 +30,10 @@ log_max_days = 3
|
|||||||
privilege_mode = true
|
privilege_mode = true
|
||||||
privilege_token = 12345678
|
privilege_token = 12345678
|
||||||
|
|
||||||
|
# heartbeat configure, it's not recommended to modify the default value
|
||||||
|
# the default value of heartbeat_timeout is 30
|
||||||
|
# heartbeat_timeout = 30
|
||||||
|
|
||||||
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
|
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
|
||||||
privilege_allow_ports = 2000-3000,3001,3003,4000-50000
|
privilege_allow_ports = 2000-3000,3001,3003,4000-50000
|
||||||
|
|
||||||
|
@ -55,15 +55,24 @@ func msgReader(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface
|
|||||||
var heartbeatTimeout bool = false
|
var heartbeatTimeout bool = false
|
||||||
timer := time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, func() {
|
timer := time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, func() {
|
||||||
heartbeatTimeout = true
|
heartbeatTimeout = true
|
||||||
c.Close()
|
if c != nil {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
if cli != nil {
|
||||||
|
// if it's not udp type, nothing will happen
|
||||||
|
cli.CloseUdpTunnel()
|
||||||
|
cli.SetCloseFlag(true)
|
||||||
|
}
|
||||||
log.Error("ProxyName [%s], heartbeatRes from frps timeout", cli.Name)
|
log.Error("ProxyName [%s], heartbeatRes from frps timeout", cli.Name)
|
||||||
})
|
})
|
||||||
defer timer.Stop()
|
defer timer.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
buf, err := c.ReadLine()
|
buf, err := c.ReadLine()
|
||||||
if err == io.EOF || c == nil || c.IsClosed() {
|
if err == io.EOF || c.IsClosed() {
|
||||||
|
timer.Stop()
|
||||||
c.Close()
|
c.Close()
|
||||||
|
cli.SetCloseFlag(true)
|
||||||
log.Warn("ProxyName [%s], frps close this control conn!", cli.Name)
|
log.Warn("ProxyName [%s], frps close this control conn!", cli.Name)
|
||||||
var delayTime time.Duration = 1
|
var delayTime time.Duration = 1
|
||||||
|
|
||||||
@ -76,11 +85,14 @@ func msgReader(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface
|
|||||||
msgSendChan = make(chan interface{}, 1024)
|
msgSendChan = make(chan interface{}, 1024)
|
||||||
go heartbeatSender(c, msgSendChan)
|
go heartbeatSender(c, msgSendChan)
|
||||||
go msgSender(cli, c, msgSendChan)
|
go msgSender(cli, c, msgSendChan)
|
||||||
|
cli.SetCloseFlag(false)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if delayTime < 60 {
|
if delayTime < 30 {
|
||||||
delayTime = delayTime * 2
|
delayTime = delayTime * 2
|
||||||
|
} else {
|
||||||
|
delayTime = 30
|
||||||
}
|
}
|
||||||
time.Sleep(delayTime * time.Second)
|
time.Sleep(delayTime * time.Second)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,9 @@ func controlWorker(c *conn.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
closeFlag = false
|
if ret == 0 {
|
||||||
|
closeFlag = false
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@ type ProxyClient struct {
|
|||||||
|
|
||||||
udpTunnel *conn.Conn
|
udpTunnel *conn.Conn
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
closeFlag bool
|
||||||
|
|
||||||
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// if proxy type is udp, keep a tcp connection for transferring udp packages
|
// if proxy type is udp, keep a tcp connection for transferring udp packages
|
||||||
@ -48,7 +51,7 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
|
|||||||
var c *conn.Conn
|
var c *conn.Conn
|
||||||
udpProcessor := NewUdpProcesser(nil, pc.LocalIp, pc.LocalPort)
|
udpProcessor := NewUdpProcesser(nil, pc.LocalIp, pc.LocalPort)
|
||||||
for {
|
for {
|
||||||
if pc.udpTunnel == nil || pc.udpTunnel.IsClosed() {
|
if !pc.IsClosed() && (pc.udpTunnel == nil || pc.udpTunnel.IsClosed()) {
|
||||||
if HttpProxy == "" {
|
if HttpProxy == "" {
|
||||||
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", addr, port))
|
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", addr, port))
|
||||||
} else {
|
} else {
|
||||||
@ -59,7 +62,7 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
|
|||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Info("ProxyName [%s], udp tunnel reconnect to server [%s:%d] success", pc.Name, addr, port)
|
log.Info("ProxyName [%s], udp tunnel connect to server [%s:%d] success", pc.Name, addr, port)
|
||||||
|
|
||||||
nowTime := time.Now().Unix()
|
nowTime := time.Now().Unix()
|
||||||
req := &msg.ControlReq{
|
req := &msg.ControlReq{
|
||||||
@ -82,8 +85,11 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
|
|||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
pc.mutex.Lock()
|
||||||
pc.udpTunnel = c
|
pc.udpTunnel = c
|
||||||
udpProcessor.UpdateTcpConn(pc.udpTunnel)
|
udpProcessor.UpdateTcpConn(pc.udpTunnel)
|
||||||
|
pc.mutex.Unlock()
|
||||||
|
|
||||||
udpProcessor.Run()
|
udpProcessor.Run()
|
||||||
}
|
}
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
@ -91,6 +97,14 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pc *ProxyClient) CloseUdpTunnel() {
|
||||||
|
pc.mutex.RLock()
|
||||||
|
defer pc.mutex.RUnlock()
|
||||||
|
if pc.udpTunnel != nil {
|
||||||
|
pc.udpTunnel.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (pc *ProxyClient) GetLocalConn() (c *conn.Conn, err error) {
|
func (pc *ProxyClient) GetLocalConn() (c *conn.Conn, err error) {
|
||||||
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", pc.LocalIp, pc.LocalPort))
|
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", pc.LocalIp, pc.LocalPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -158,3 +172,15 @@ func (pc *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err err
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pc *ProxyClient) SetCloseFlag(closeFlag bool) {
|
||||||
|
pc.mutex.Lock()
|
||||||
|
defer pc.mutex.Unlock()
|
||||||
|
pc.closeFlag = closeFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProxyClient) IsClosed() bool {
|
||||||
|
pc.mutex.RLock()
|
||||||
|
defer pc.mutex.RUnlock()
|
||||||
|
return pc.closeFlag
|
||||||
|
}
|
||||||
|
@ -33,8 +33,8 @@ var (
|
|||||||
LogLevel string = "info"
|
LogLevel string = "info"
|
||||||
LogMaxDays int64 = 3
|
LogMaxDays int64 = 3
|
||||||
PrivilegeToken string = ""
|
PrivilegeToken string = ""
|
||||||
HeartBeatInterval int64 = 20
|
HeartBeatInterval int64 = 10
|
||||||
HeartBeatTimeout int64 = 90
|
HeartBeatTimeout int64 = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
var ProxyClients map[string]*ProxyClient = make(map[string]*ProxyClient)
|
var ProxyClients map[string]*ProxyClient = make(map[string]*ProxyClient)
|
||||||
@ -98,6 +98,34 @@ func LoadConf(confFile string) (err error) {
|
|||||||
authToken = tmpStr
|
authToken = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmpStr, ok = conf.Get("common", "heartbeat_timeout")
|
||||||
|
if ok {
|
||||||
|
v, err := strconv.ParseInt(tmpStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
|
||||||
|
} else {
|
||||||
|
HeartBeatTimeout = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpStr, ok = conf.Get("common", "heartbeat_interval")
|
||||||
|
if ok {
|
||||||
|
v, err := strconv.ParseInt(tmpStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Parse conf error: heartbeat_interval is incorrect")
|
||||||
|
} else {
|
||||||
|
HeartBeatInterval = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if HeartBeatInterval <= 0 {
|
||||||
|
return fmt.Errorf("Parse conf error: heartbeat_interval is incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
if HeartBeatTimeout < HeartBeatInterval {
|
||||||
|
return fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect, heartbeat_timeout is less than heartbeat_interval")
|
||||||
|
}
|
||||||
|
|
||||||
// proxies
|
// proxies
|
||||||
for name, section := range conf {
|
for name, section := range conf {
|
||||||
if name != "common" {
|
if name != "common" {
|
||||||
|
@ -51,7 +51,7 @@ var (
|
|||||||
// if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected
|
// if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected
|
||||||
PrivilegeAllowPorts map[int64]struct{}
|
PrivilegeAllowPorts map[int64]struct{}
|
||||||
MaxPoolCount int64 = 100
|
MaxPoolCount int64 = 100
|
||||||
HeartBeatTimeout int64 = 90
|
HeartBeatTimeout int64 = 30
|
||||||
UserConnTimeout int64 = 10
|
UserConnTimeout int64 = 10
|
||||||
|
|
||||||
VhostHttpMuxer *vhost.HttpMuxer
|
VhostHttpMuxer *vhost.HttpMuxer
|
||||||
@ -237,6 +237,16 @@ func loadCommonConf(confFile string) error {
|
|||||||
if ok {
|
if ok {
|
||||||
SubDomainHost = strings.ToLower(strings.TrimSpace(SubDomainHost))
|
SubDomainHost = strings.ToLower(strings.TrimSpace(SubDomainHost))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmpStr, ok = conf.Get("common", "heartbeat_timeout")
|
||||||
|
if ok {
|
||||||
|
v, err := strconv.ParseInt(tmpStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
|
||||||
|
} else {
|
||||||
|
HeartBeatTimeout = v
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +405,9 @@ func CreateProxy(s *ProxyServer) error {
|
|||||||
if oldServer.Status == consts.Working {
|
if oldServer.Status == consts.Working {
|
||||||
return fmt.Errorf("this proxy is already working now")
|
return fmt.Errorf("this proxy is already working now")
|
||||||
}
|
}
|
||||||
|
oldServer.Lock()
|
||||||
oldServer.Release()
|
oldServer.Release()
|
||||||
|
oldServer.Unlock()
|
||||||
if oldServer.PrivilegeMode {
|
if oldServer.PrivilegeMode {
|
||||||
delete(ProxyServers, s.Name)
|
delete(ProxyServers, s.Name)
|
||||||
}
|
}
|
||||||
@ -403,7 +415,6 @@ func CreateProxy(s *ProxyServer) error {
|
|||||||
ProxyServers[s.Name] = s
|
ProxyServers[s.Name] = s
|
||||||
metric.SetProxyInfo(s.Name, s.Type, s.BindAddr, s.UseEncryption, s.UseGzip,
|
metric.SetProxyInfo(s.Name, s.Type, s.BindAddr, s.UseEncryption, s.UseGzip,
|
||||||
s.PrivilegeMode, s.CustomDomains, s.Locations, s.ListenPort)
|
s.PrivilegeMode, s.CustomDomains, s.Locations, s.ListenPort)
|
||||||
s.Init()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,8 @@ func NewProxyServerFromCtlMsg(req *msg.ControlReq) (p *ProxyServer) {
|
|||||||
p.HostHeaderRewrite = req.HostHeaderRewrite
|
p.HostHeaderRewrite = req.HostHeaderRewrite
|
||||||
p.HttpUserName = req.HttpUserName
|
p.HttpUserName = req.HttpUserName
|
||||||
p.HttpPassWord = req.HttpPassWord
|
p.HttpPassWord = req.HttpPassWord
|
||||||
|
|
||||||
|
p.Init()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,10 +278,14 @@ func (p *ProxyServer) Start(c *conn.Conn) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyServer) Close() {
|
func (p *ProxyServer) Close() {
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
|
||||||
|
oldStatus := p.Status
|
||||||
p.Release()
|
p.Release()
|
||||||
|
|
||||||
// if the proxy created by PrivilegeMode, delete it when closed
|
// if the proxy created by PrivilegeMode, delete it when closed
|
||||||
if p.PrivilegeMode {
|
if p.PrivilegeMode && oldStatus != consts.Closed {
|
||||||
// NOTE: this will take the global ProxyServerMap's lock
|
// NOTE: this will take the global ProxyServerMap's lock
|
||||||
// if we only want to release resources, use Release() instead
|
// if we only want to release resources, use Release() instead
|
||||||
DeleteProxy(p.Name)
|
DeleteProxy(p.Name)
|
||||||
@ -287,9 +293,6 @@ func (p *ProxyServer) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyServer) Release() {
|
func (p *ProxyServer) Release() {
|
||||||
p.Lock()
|
|
||||||
defer p.Unlock()
|
|
||||||
|
|
||||||
if p.Status != consts.Closed {
|
if p.Status != consts.Closed {
|
||||||
p.Status = consts.Closed
|
p.Status = consts.Closed
|
||||||
for _, l := range p.listeners {
|
for _, l := range p.listeners {
|
||||||
@ -297,10 +300,22 @@ func (p *ProxyServer) Release() {
|
|||||||
l.Close()
|
l.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(p.ctlMsgChan)
|
if p.ctlMsgChan != nil {
|
||||||
close(p.workConnChan)
|
close(p.ctlMsgChan)
|
||||||
close(p.udpSenderChan)
|
p.ctlMsgChan = nil
|
||||||
close(p.closeChan)
|
}
|
||||||
|
if p.workConnChan != nil {
|
||||||
|
close(p.workConnChan)
|
||||||
|
p.workConnChan = nil
|
||||||
|
}
|
||||||
|
if p.udpSenderChan != nil {
|
||||||
|
close(p.udpSenderChan)
|
||||||
|
p.udpSenderChan = nil
|
||||||
|
}
|
||||||
|
if p.closeChan != nil {
|
||||||
|
close(p.closeChan)
|
||||||
|
p.closeChan = nil
|
||||||
|
}
|
||||||
if p.CtlConn != nil {
|
if p.CtlConn != nil {
|
||||||
p.CtlConn.Close()
|
p.CtlConn.Close()
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version string = "0.9.1"
|
var version string = "0.9.2"
|
||||||
|
|
||||||
func Full() string {
|
func Full() string {
|
||||||
return version
|
return version
|
||||||
|
Loading…
Reference in New Issue
Block a user