Browse Source

Merge pull request #217 from fatedier/dev

bump version to 0.9.2
fatedier 8 years ago
parent
commit
edb97abf50

+ 15 - 7
Makefile.cross-compiles

@@ -3,15 +3,23 @@ export GO15VENDOREXPERIMENT := 1
 
 
 all: build
 all: build
 
 
-build: gox app more
-
-gox:
-	go get github.com/mitchellh/gox
+build: app
 
 
 app:
 app:
-	gox -osarch "darwin/386 darwin/amd64 linux/386 linux/amd64 linux/arm windows/386 windows/amd64" ./src/...
-
-more:
+	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
+	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

+ 2 - 2
README.md

@@ -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)

+ 1 - 1
README_zh.md

@@ -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)

+ 4 - 0
conf/frpc.ini

@@ -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]

+ 4 - 0
conf/frps.ini

@@ -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
 
 

+ 15 - 3
src/cmd/frpc/control.go

@@ -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)
 			}
 			}

+ 3 - 1
src/cmd/frps/control.go

@@ -85,7 +85,9 @@ func controlWorker(c *conn.Conn) {
 			return
 			return
 		}
 		}
 	} else {
 	} else {
-		closeFlag = false
+		if ret == 0 {
+			closeFlag = false
+		}
 		return
 		return
 	}
 	}
 
 

+ 28 - 2
src/models/client/client.go

@@ -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
+}

+ 30 - 2
src/models/client/config.go

@@ -33,8 +33,8 @@ var (
 	LogLevel          string = "info"
 	LogLevel          string = "info"
 	LogMaxDays        int64  = 3
 	LogMaxDays        int64  = 3
 	PrivilegeToken    string = ""
 	PrivilegeToken    string = ""
-	HeartBeatInterval int64  = 20
-	HeartBeatTimeout  int64  = 90
+	HeartBeatInterval int64  = 10
+	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" {

+ 13 - 2
src/models/server/config.go

@@ -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
 }
 }
 
 

+ 23 - 8
src/models/server/server.go

@@ -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)
-		close(p.workConnChan)
-		close(p.udpSenderChan)
-		close(p.closeChan)
+		if p.ctlMsgChan != nil {
+			close(p.ctlMsgChan)
+			p.ctlMsgChan = nil
+		}
+		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()
 		}
 		}

+ 1 - 1
src/utils/version/version.go

@@ -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