Browse Source

close all proxies if protocol = kcp

fatedier 7 years ago
parent
commit
aede4e54f8
4 changed files with 57 additions and 3 deletions
  1. 34 3
      client/control.go
  2. 4 0
      client/service.go
  3. 18 0
      cmd/frpc/main.go
  4. 1 0
      server/control.go

+ 34 - 3
client/control.go

@@ -24,6 +24,7 @@ import (
 	"github.com/fatedier/frp/models/config"
 	"github.com/fatedier/frp/models/msg"
 	"github.com/fatedier/frp/utils/crypto"
+	"github.com/fatedier/frp/utils/errors"
 	"github.com/fatedier/frp/utils/log"
 	frpNet "github.com/fatedier/frp/utils/net"
 	"github.com/fatedier/frp/utils/util"
@@ -69,8 +70,8 @@ type Control struct {
 	// run id got from server
 	runId string
 
-	// connection or other error happens , control will try to reconnect to server
-	closed int32
+	// if we call close() in control, do not reconnect to server
+	exit bool
 
 	// goroutines can block by reading from this channel, it will be closed only in reader() when control connection is closed
 	closedCh chan int
@@ -181,7 +182,10 @@ func (ctl *Control) NewWorkConn() {
 	workConn.AddLogPrefix(startMsg.ProxyName)
 
 	// dispatch this work connection to related proxy
-	if pxy, ok := ctl.proxies[startMsg.ProxyName]; ok {
+	ctl.mu.RLock()
+	pxy, ok := ctl.proxies[startMsg.ProxyName]
+	ctl.mu.RUnlock()
+	if ok {
 		workConn.Debug("start a new work connection, localAddr: %s remoteAddr: %s", workConn.LocalAddr().String(), workConn.RemoteAddr().String())
 		go pxy.InWorkConn(workConn)
 	} else {
@@ -189,6 +193,20 @@ func (ctl *Control) NewWorkConn() {
 	}
 }
 
+func (ctl *Control) Close() error {
+	ctl.mu.Lock()
+	ctl.exit = true
+	err := errors.PanicToError(func() {
+		for name, _ := range ctl.proxies {
+			ctl.sendCh <- &msg.CloseProxy{
+				ProxyName: name,
+			}
+		}
+	})
+	ctl.mu.Unlock()
+	return err
+}
+
 func (ctl *Control) init() {
 	ctl.sendCh = make(chan msg.Message, 10)
 	ctl.readCh = make(chan msg.Message, 10)
@@ -377,7 +395,10 @@ func (ctl *Control) manager() {
 					ctl.Warn("[%s] no proxy conf found", m.ProxyName)
 					continue
 				}
+
+				ctl.mu.RLock()
 				oldPxy, ok := ctl.proxies[m.ProxyName]
+				ctl.mu.RUnlock()
 				if ok {
 					oldPxy.Close()
 				}
@@ -389,7 +410,9 @@ func (ctl *Control) manager() {
 					}
 					continue
 				}
+				ctl.mu.Lock()
 				ctl.proxies[m.ProxyName] = pxy
+				ctl.mu.Unlock()
 				ctl.Info("[%s] start proxy success", m.ProxyName)
 			case *msg.Pong:
 				ctl.lastPong = time.Now()
@@ -429,6 +452,14 @@ func (ctl *Control) controler() {
 				for _, pxy := range ctl.proxies {
 					pxy.Close()
 				}
+				// if ctl.exit is true, just exit
+				ctl.mu.RLock()
+				exit := ctl.exit
+				ctl.mu.RUnlock()
+				if exit {
+					return
+				}
+
 				time.Sleep(time.Second)
 
 				// loop util reconnect to server success

+ 4 - 0
client/service.go

@@ -41,3 +41,7 @@ func (svr *Service) Run() error {
 	<-svr.closedCh
 	return nil
 }
+
+func (svr *Service) Close() error {
+	return svr.ctl.Close()
+}

+ 18 - 0
cmd/frpc/main.go

@@ -17,8 +17,11 @@ package main
 import (
 	"fmt"
 	"os"
+	"os/signal"
 	"strconv"
 	"strings"
+	"syscall"
+	"time"
 
 	docopt "github.com/docopt/docopt-go"
 	ini "github.com/vaughan0/go-ini"
@@ -116,9 +119,24 @@ func main() {
 		config.ClientCommonCfg.LogLevel, config.ClientCommonCfg.LogMaxDays)
 
 	svr := client.NewService(pxyCfgs, vistorCfgs)
+
+	// Capture the exit signal if we use kcp.
+	if config.ClientCommonCfg.Protocol == "kcp" {
+		go HandleSignal(svr)
+	}
+
 	err = svr.Run()
 	if err != nil {
 		fmt.Println(err)
 		os.Exit(1)
 	}
 }
+
+func HandleSignal(svr *client.Service) {
+	ch := make(chan os.Signal)
+	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
+	<-ch
+	svr.Close()
+	time.Sleep(250 * time.Millisecond)
+	os.Exit(0)
+}

+ 1 - 0
server/control.go

@@ -378,6 +378,7 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
 
 	pxy.Close()
 	ctl.svr.DelProxy(pxy.GetName())
+	delete(ctl.proxies, closeMsg.ProxyName)
 	StatsCloseProxy(pxy.GetName(), pxy.GetConf().GetBaseInfo().ProxyType)
 	return
 }