Browse Source

Merge pull request #1401 from velovix/issue-1387_client-conf-as-argument

Pass client configuration as an argument
fatedier 5 years ago
parent
commit
bc4df74b5e

+ 1 - 2
client/admin.go

@@ -21,7 +21,6 @@ import (
 	"time"
 
 	"github.com/fatedier/frp/assets"
-	"github.com/fatedier/frp/g"
 	frpNet "github.com/fatedier/frp/utils/net"
 
 	"github.com/gorilla/mux"
@@ -36,7 +35,7 @@ func (svr *Service) RunAdminServer(addr string, port int) (err error) {
 	// url router
 	router := mux.NewRouter()
 
-	user, passwd := g.GlbClientCfg.AdminUser, g.GlbClientCfg.AdminPwd
+	user, passwd := svr.cfg.AdminUser, svr.cfg.AdminPwd
 	router.Use(frpNet.NewHttpAuthMiddleware(user, passwd).Middleware)
 
 	// api, see dashboard_api.go

+ 18 - 19
client/admin_api.go

@@ -23,7 +23,6 @@ import (
 	"strings"
 
 	"github.com/fatedier/frp/client/proxy"
-	"github.com/fatedier/frp/g"
 	"github.com/fatedier/frp/models/config"
 	"github.com/fatedier/frp/utils/log"
 )
@@ -47,7 +46,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
 		}
 	}()
 
-	content, err := config.GetRenderedConfFromFile(g.GlbClientCfg.CfgFile)
+	content, err := config.GetRenderedConfFromFile(svr.cfgFile)
 	if err != nil {
 		res.Code = 400
 		res.Msg = err.Error()
@@ -55,7 +54,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	newCommonCfg, err := config.UnmarshalClientConfFromIni(nil, content)
+	newCommonCfg, err := config.UnmarshalClientConfFromIni(content)
 	if err != nil {
 		res.Code = 400
 		res.Msg = err.Error()
@@ -63,7 +62,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(g.GlbClientCfg.User, content, newCommonCfg.Start)
+	pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(svr.cfg.User, content, newCommonCfg.Start)
 	if err != nil {
 		res.Code = 400
 		res.Msg = err.Error()
@@ -107,7 +106,7 @@ func (a ByProxyStatusResp) Len() int           { return len(a) }
 func (a ByProxyStatusResp) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
 func (a ByProxyStatusResp) Less(i, j int) bool { return strings.Compare(a[i].Name, a[j].Name) < 0 }
 
-func NewProxyStatusResp(status *proxy.ProxyStatus) ProxyStatusResp {
+func NewProxyStatusResp(status *proxy.ProxyStatus, serverAddr string) ProxyStatusResp {
 	psr := ProxyStatusResp{
 		Name:   status.Name,
 		Type:   status.Type,
@@ -121,18 +120,18 @@ func NewProxyStatusResp(status *proxy.ProxyStatus) ProxyStatusResp {
 		}
 		psr.Plugin = cfg.Plugin
 		if status.Err != "" {
-			psr.RemoteAddr = fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, cfg.RemotePort)
+			psr.RemoteAddr = fmt.Sprintf("%s:%d", serverAddr, cfg.RemotePort)
 		} else {
-			psr.RemoteAddr = g.GlbClientCfg.ServerAddr + status.RemoteAddr
+			psr.RemoteAddr = serverAddr + status.RemoteAddr
 		}
 	case *config.UdpProxyConf:
 		if cfg.LocalPort != 0 {
 			psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort)
 		}
 		if status.Err != "" {
-			psr.RemoteAddr = fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, cfg.RemotePort)
+			psr.RemoteAddr = fmt.Sprintf("%s:%d", serverAddr, cfg.RemotePort)
 		} else {
-			psr.RemoteAddr = g.GlbClientCfg.ServerAddr + status.RemoteAddr
+			psr.RemoteAddr = serverAddr + status.RemoteAddr
 		}
 	case *config.HttpProxyConf:
 		if cfg.LocalPort != 0 {
@@ -184,17 +183,17 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
 	for _, status := range ps {
 		switch status.Type {
 		case "tcp":
-			res.Tcp = append(res.Tcp, NewProxyStatusResp(status))
+			res.Tcp = append(res.Tcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
 		case "udp":
-			res.Udp = append(res.Udp, NewProxyStatusResp(status))
+			res.Udp = append(res.Udp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
 		case "http":
-			res.Http = append(res.Http, NewProxyStatusResp(status))
+			res.Http = append(res.Http, NewProxyStatusResp(status, svr.cfg.ServerAddr))
 		case "https":
-			res.Https = append(res.Https, NewProxyStatusResp(status))
+			res.Https = append(res.Https, NewProxyStatusResp(status, svr.cfg.ServerAddr))
 		case "stcp":
-			res.Stcp = append(res.Stcp, NewProxyStatusResp(status))
+			res.Stcp = append(res.Stcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
 		case "xtcp":
-			res.Xtcp = append(res.Xtcp, NewProxyStatusResp(status))
+			res.Xtcp = append(res.Xtcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
 		}
 	}
 	sort.Sort(ByProxyStatusResp(res.Tcp))
@@ -219,14 +218,14 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, r *http.Request) {
 		}
 	}()
 
-	if g.GlbClientCfg.CfgFile == "" {
+	if svr.cfgFile == "" {
 		res.Code = 400
 		res.Msg = "frpc has no config file path"
 		log.Warn("%s", res.Msg)
 		return
 	}
 
-	content, err := config.GetRenderedConfFromFile(g.GlbClientCfg.CfgFile)
+	content, err := config.GetRenderedConfFromFile(svr.cfgFile)
 	if err != nil {
 		res.Code = 400
 		res.Msg = err.Error()
@@ -277,7 +276,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
 
 	// get token from origin content
 	token := ""
-	b, err := ioutil.ReadFile(g.GlbClientCfg.CfgFile)
+	b, err := ioutil.ReadFile(svr.cfgFile)
 	if err != nil {
 		res.Code = 400
 		res.Msg = err.Error()
@@ -316,7 +315,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
 	}
 	content = strings.Join(newRows, "\n")
 
-	err = ioutil.WriteFile(g.GlbClientCfg.CfgFile, []byte(content), 0644)
+	err = ioutil.WriteFile(svr.cfgFile, []byte(content), 0644)
 	if err != nil {
 		res.Code = 500
 		res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)

+ 20 - 11
client/control.go

@@ -23,7 +23,6 @@ import (
 	"time"
 
 	"github.com/fatedier/frp/client/proxy"
-	"github.com/fatedier/frp/g"
 	"github.com/fatedier/frp/models/config"
 	"github.com/fatedier/frp/models/msg"
 	"github.com/fatedier/frp/utils/log"
@@ -65,16 +64,24 @@ type Control struct {
 	// last time got the Pong message
 	lastPong time.Time
 
+	// The client configuration
+	clientCfg config.ClientCommonConf
+
 	readerShutdown     *shutdown.Shutdown
 	writerShutdown     *shutdown.Shutdown
 	msgHandlerShutdown *shutdown.Shutdown
 
+	// The UDP port that the server is listening on
+	serverUDPPort int
+
 	mu sync.RWMutex
 
 	log.Logger
 }
 
-func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) *Control {
+func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, clientCfg config.ClientCommonConf,
+	pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, serverUDPPort int) *Control {
+
 	ctl := &Control{
 		runId:              runId,
 		conn:               conn,
@@ -84,12 +91,14 @@ func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, pxyCfgs m
 		readCh:             make(chan msg.Message, 100),
 		closedCh:           make(chan struct{}),
 		closedDoneCh:       make(chan struct{}),
+		clientCfg:          clientCfg,
 		readerShutdown:     shutdown.New(),
 		writerShutdown:     shutdown.New(),
 		msgHandlerShutdown: shutdown.New(),
+		serverUDPPort:      serverUDPPort,
 		Logger:             log.NewPrefixLogger(""),
 	}
-	ctl.pm = proxy.NewProxyManager(ctl.sendCh, runId)
+	ctl.pm = proxy.NewProxyManager(ctl.sendCh, runId, clientCfg, serverUDPPort)
 
 	ctl.vm = NewVisitorManager(ctl)
 	ctl.vm.Reload(visitorCfgs)
@@ -161,7 +170,7 @@ func (ctl *Control) ClosedDoneCh() <-chan struct{} {
 
 // connectServer return a new connection to frps
 func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
-	if g.GlbClientCfg.TcpMux {
+	if ctl.clientCfg.TcpMux {
 		stream, errRet := ctl.session.OpenStream()
 		if errRet != nil {
 			err = errRet
@@ -171,13 +180,13 @@ func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
 		conn = frpNet.WrapConn(stream)
 	} else {
 		var tlsConfig *tls.Config
-		if g.GlbClientCfg.TLSEnable {
+		if ctl.clientCfg.TLSEnable {
 			tlsConfig = &tls.Config{
 				InsecureSkipVerify: true,
 			}
 		}
-		conn, err = frpNet.ConnectServerByProxyWithTLS(g.GlbClientCfg.HttpProxy, g.GlbClientCfg.Protocol,
-			fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerPort), tlsConfig)
+		conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HttpProxy, ctl.clientCfg.Protocol,
+			fmt.Sprintf("%s:%d", ctl.clientCfg.ServerAddr, ctl.clientCfg.ServerPort), tlsConfig)
 		if err != nil {
 			ctl.Warn("start new connection to server error: %v", err)
 			return
@@ -197,7 +206,7 @@ func (ctl *Control) reader() {
 	defer ctl.readerShutdown.Done()
 	defer close(ctl.closedCh)
 
-	encReader := crypto.NewReader(ctl.conn, []byte(g.GlbClientCfg.Token))
+	encReader := crypto.NewReader(ctl.conn, []byte(ctl.clientCfg.Token))
 	for {
 		if m, err := msg.ReadMsg(encReader); err != nil {
 			if err == io.EOF {
@@ -217,7 +226,7 @@ func (ctl *Control) reader() {
 // writer writes messages got from sendCh to frps
 func (ctl *Control) writer() {
 	defer ctl.writerShutdown.Done()
-	encWriter, err := crypto.NewWriter(ctl.conn, []byte(g.GlbClientCfg.Token))
+	encWriter, err := crypto.NewWriter(ctl.conn, []byte(ctl.clientCfg.Token))
 	if err != nil {
 		ctl.conn.Error("crypto new writer error: %v", err)
 		ctl.conn.Close()
@@ -246,7 +255,7 @@ func (ctl *Control) msgHandler() {
 	}()
 	defer ctl.msgHandlerShutdown.Done()
 
-	hbSend := time.NewTicker(time.Duration(g.GlbClientCfg.HeartBeatInterval) * time.Second)
+	hbSend := time.NewTicker(time.Duration(ctl.clientCfg.HeartBeatInterval) * time.Second)
 	defer hbSend.Stop()
 	hbCheck := time.NewTicker(time.Second)
 	defer hbCheck.Stop()
@@ -260,7 +269,7 @@ func (ctl *Control) msgHandler() {
 			ctl.Debug("send heartbeat to server")
 			ctl.sendCh <- &msg.Ping{}
 		case <-hbCheck.C:
-			if time.Since(ctl.lastPong) > time.Duration(g.GlbClientCfg.HeartBeatTimeout)*time.Second {
+			if time.Since(ctl.lastPong) > time.Duration(ctl.clientCfg.HeartBeatTimeout)*time.Second {
 				ctl.Warn("heartbeat timeout")
 				// let reader() stop
 				ctl.conn.Close()

+ 13 - 10
client/proxy/proxy.go

@@ -25,7 +25,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/fatedier/frp/g"
 	"github.com/fatedier/frp/models/config"
 	"github.com/fatedier/frp/models/msg"
 	"github.com/fatedier/frp/models/plugin"
@@ -51,9 +50,11 @@ type Proxy interface {
 	log.Logger
 }
 
-func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
+func NewProxy(pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) {
 	baseProxy := BaseProxy{
-		Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
+		Logger:        log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
+		clientCfg:     clientCfg,
+		serverUDPPort: serverUDPPort,
 	}
 	switch cfg := pxyConf.(type) {
 	case *config.TcpProxyConf:
@@ -91,8 +92,10 @@ func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
 }
 
 type BaseProxy struct {
-	closed bool
-	mu     sync.RWMutex
+	closed        bool
+	mu            sync.RWMutex
+	clientCfg     config.ClientCommonConf
+	serverUDPPort int
 	log.Logger
 }
 
@@ -122,7 +125,7 @@ func (pxy *TcpProxy) Close() {
 
 func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
 	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
-		[]byte(g.GlbClientCfg.Token), m)
+		[]byte(pxy.clientCfg.Token), m)
 }
 
 // HTTP
@@ -151,7 +154,7 @@ func (pxy *HttpProxy) Close() {
 
 func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
 	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
-		[]byte(g.GlbClientCfg.Token), m)
+		[]byte(pxy.clientCfg.Token), m)
 }
 
 // HTTPS
@@ -180,7 +183,7 @@ func (pxy *HttpsProxy) Close() {
 
 func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
 	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
-		[]byte(g.GlbClientCfg.Token), m)
+		[]byte(pxy.clientCfg.Token), m)
 }
 
 // STCP
@@ -209,7 +212,7 @@ func (pxy *StcpProxy) Close() {
 
 func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
 	HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
-		[]byte(g.GlbClientCfg.Token), m)
+		[]byte(pxy.clientCfg.Token), m)
 }
 
 // XTCP
@@ -250,7 +253,7 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
 		Sid:       natHoleSidMsg.Sid,
 	}
 	raddr, _ := net.ResolveUDPAddr("udp",
-		fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerUdpPort))
+		fmt.Sprintf("%s:%d", pxy.clientCfg.ServerAddr, pxy.serverUDPPort))
 	clientConn, err := net.DialUDP("udp", nil, raddr)
 	defer clientConn.Close()
 

+ 14 - 7
client/proxy/proxy_manager.go

@@ -20,17 +20,24 @@ type ProxyManager struct {
 	closed bool
 	mu     sync.RWMutex
 
+	clientCfg config.ClientCommonConf
+
+	// The UDP port that the server is listening on
+	serverUDPPort int
+
 	logPrefix string
 	log.Logger
 }
 
-func NewProxyManager(msgSendCh chan (msg.Message), logPrefix string) *ProxyManager {
+func NewProxyManager(msgSendCh chan (msg.Message), logPrefix string, clientCfg config.ClientCommonConf, serverUDPPort int) *ProxyManager {
 	return &ProxyManager{
-		proxies:   make(map[string]*ProxyWrapper),
-		sendCh:    msgSendCh,
-		closed:    false,
-		logPrefix: logPrefix,
-		Logger:    log.NewPrefixLogger(logPrefix),
+		proxies:       make(map[string]*ProxyWrapper),
+		sendCh:        msgSendCh,
+		closed:        false,
+		clientCfg:     clientCfg,
+		serverUDPPort: serverUDPPort,
+		logPrefix:     logPrefix,
+		Logger:        log.NewPrefixLogger(logPrefix),
 	}
 }
 
@@ -126,7 +133,7 @@ func (pm *ProxyManager) Reload(pxyCfgs map[string]config.ProxyConf) {
 	addPxyNames := make([]string, 0)
 	for name, cfg := range pxyCfgs {
 		if _, ok := pm.proxies[name]; !ok {
-			pxy := NewProxyWrapper(cfg, pm.HandleEvent, pm.logPrefix)
+			pxy := NewProxyWrapper(cfg, pm.clientCfg, pm.HandleEvent, pm.logPrefix, pm.serverUDPPort)
 			pm.proxies[name] = pxy
 			addPxyNames = append(addPxyNames, name)
 

+ 2 - 2
client/proxy/proxy_wrapper.go

@@ -65,7 +65,7 @@ type ProxyWrapper struct {
 	log.Logger
 }
 
-func NewProxyWrapper(cfg config.ProxyConf, eventHandler event.EventHandler, logPrefix string) *ProxyWrapper {
+func NewProxyWrapper(cfg config.ProxyConf, clientCfg config.ClientCommonConf, eventHandler event.EventHandler, logPrefix string, serverUDPPort int) *ProxyWrapper {
 	baseInfo := cfg.GetBaseInfo()
 	pw := &ProxyWrapper{
 		ProxyStatus: ProxyStatus{
@@ -90,7 +90,7 @@ func NewProxyWrapper(cfg config.ProxyConf, eventHandler event.EventHandler, logP
 		pw.Trace("enable health check monitor")
 	}
 
-	pw.pxy = NewProxy(pw.Cfg)
+	pw.pxy = NewProxy(pw.Cfg, clientCfg, serverUDPPort)
 	return pw
 }
 

+ 26 - 17
client/service.go

@@ -24,7 +24,6 @@ import (
 	"time"
 
 	"github.com/fatedier/frp/assets"
-	"github.com/fatedier/frp/g"
 	"github.com/fatedier/frp/models/config"
 	"github.com/fatedier/frp/models/msg"
 	"github.com/fatedier/frp/utils/log"
@@ -43,16 +42,26 @@ type Service struct {
 	ctl   *Control
 	ctlMu sync.RWMutex
 
+	cfg         config.ClientCommonConf
 	pxyCfgs     map[string]config.ProxyConf
 	visitorCfgs map[string]config.VisitorConf
 	cfgMu       sync.RWMutex
 
+	// The configuration file used to initialize this client, or an empty
+	// string if no configuration file was used.
+	cfgFile string
+
+	// This is configured by the login response from frps
+	serverUDPPort int
+
 	exit     uint32 // 0 means not exit
 	closedCh chan int
 }
 
-func NewService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (svr *Service, err error) {
+func NewService(cfg config.ClientCommonConf, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (svr *Service, err error) {
 	svr = &Service{
+		cfg:         cfg,
+		cfgFile:     cfgFile,
 		pxyCfgs:     pxyCfgs,
 		visitorCfgs: visitorCfgs,
 		exit:        0,
@@ -76,14 +85,14 @@ func (svr *Service) Run() error {
 
 			// if login_fail_exit is true, just exit this program
 			// otherwise sleep a while and try again to connect to server
-			if g.GlbClientCfg.LoginFailExit {
+			if svr.cfg.LoginFailExit {
 				return err
 			} else {
 				time.Sleep(10 * time.Second)
 			}
 		} else {
 			// login success
-			ctl := NewControl(svr.runId, conn, session, svr.pxyCfgs, svr.visitorCfgs)
+			ctl := NewControl(svr.runId, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort)
 			ctl.Run()
 			svr.ctlMu.Lock()
 			svr.ctl = ctl
@@ -94,18 +103,18 @@ func (svr *Service) Run() error {
 
 	go svr.keepControllerWorking()
 
-	if g.GlbClientCfg.AdminPort != 0 {
+	if svr.cfg.AdminPort != 0 {
 		// Init admin server assets
-		err := assets.Load(g.GlbClientCfg.AssetsDir)
+		err := assets.Load(svr.cfg.AssetsDir)
 		if err != nil {
 			return fmt.Errorf("Load assets error: %v", err)
 		}
 
-		err = svr.RunAdminServer(g.GlbClientCfg.AdminAddr, g.GlbClientCfg.AdminPort)
+		err = svr.RunAdminServer(svr.cfg.AdminAddr, svr.cfg.AdminPort)
 		if err != nil {
 			log.Warn("run admin server error: %v", err)
 		}
-		log.Info("admin server listen on %s:%d", g.GlbClientCfg.AdminAddr, g.GlbClientCfg.AdminPort)
+		log.Info("admin server listen on %s:%d", svr.cfg.AdminAddr, svr.cfg.AdminPort)
 	}
 
 	<-svr.closedCh
@@ -137,7 +146,7 @@ func (svr *Service) keepControllerWorking() {
 			// reconnect success, init delayTime
 			delayTime = time.Second
 
-			ctl := NewControl(svr.runId, conn, session, svr.pxyCfgs, svr.visitorCfgs)
+			ctl := NewControl(svr.runId, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort)
 			ctl.Run()
 			svr.ctlMu.Lock()
 			svr.ctl = ctl
@@ -152,13 +161,13 @@ func (svr *Service) keepControllerWorking() {
 // session: if it's not nil, using tcp mux
 func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error) {
 	var tlsConfig *tls.Config
-	if g.GlbClientCfg.TLSEnable {
+	if svr.cfg.TLSEnable {
 		tlsConfig = &tls.Config{
 			InsecureSkipVerify: true,
 		}
 	}
-	conn, err = frpNet.ConnectServerByProxyWithTLS(g.GlbClientCfg.HttpProxy, g.GlbClientCfg.Protocol,
-		fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerPort), tlsConfig)
+	conn, err = frpNet.ConnectServerByProxyWithTLS(svr.cfg.HttpProxy, svr.cfg.Protocol,
+		fmt.Sprintf("%s:%d", svr.cfg.ServerAddr, svr.cfg.ServerPort), tlsConfig)
 	if err != nil {
 		return
 	}
@@ -172,7 +181,7 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
 		}
 	}()
 
-	if g.GlbClientCfg.TcpMux {
+	if svr.cfg.TcpMux {
 		fmuxCfg := fmux.DefaultConfig()
 		fmuxCfg.KeepAliveInterval = 20 * time.Second
 		fmuxCfg.LogOutput = ioutil.Discard
@@ -193,10 +202,10 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
 	loginMsg := &msg.Login{
 		Arch:         runtime.GOARCH,
 		Os:           runtime.GOOS,
-		PoolCount:    g.GlbClientCfg.PoolCount,
-		User:         g.GlbClientCfg.User,
+		PoolCount:    svr.cfg.PoolCount,
+		User:         svr.cfg.User,
 		Version:      version.Full(),
-		PrivilegeKey: util.GetAuthKey(g.GlbClientCfg.Token, now),
+		PrivilegeKey: util.GetAuthKey(svr.cfg.Token, now),
 		Timestamp:    now,
 		RunId:        svr.runId,
 	}
@@ -219,7 +228,7 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
 	}
 
 	svr.runId = loginRespMsg.RunId
-	g.GlbClientCfg.ServerUdpPort = loginRespMsg.ServerUdpPort
+	svr.serverUDPPort = loginRespMsg.ServerUdpPort
 	log.Info("login to server success, get run id [%s], server udp port [%d]", loginRespMsg.RunId, loginRespMsg.ServerUdpPort)
 	return
 }

+ 2 - 3
client/visitor.go

@@ -23,7 +23,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/fatedier/frp/g"
 	"github.com/fatedier/frp/models/config"
 	"github.com/fatedier/frp/models/msg"
 	"github.com/fatedier/frp/utils/log"
@@ -193,13 +192,13 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
 	defer userConn.Close()
 
 	sv.Debug("get a new xtcp user connection")
-	if g.GlbClientCfg.ServerUdpPort == 0 {
+	if sv.ctl.serverUDPPort == 0 {
 		sv.Error("xtcp is not supported by server")
 		return
 	}
 
 	raddr, err := net.ResolveUDPAddr("udp",
-		fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerUdpPort))
+		fmt.Sprintf("%s:%d", sv.ctl.clientCfg.ServerAddr, sv.ctl.serverUDPPort))
 	if err != nil {
 		sv.Error("resolve server UDP addr error")
 		return

+ 2 - 2
cmd/frpc/sub/http.go

@@ -54,7 +54,7 @@ var httpCmd = &cobra.Command{
 	Use:   "http",
 	Short: "Run frpc with a single http proxy",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		err := parseClientCommonCfg(CfgFileTypeCmd, "")
+		clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)
@@ -87,7 +87,7 @@ var httpCmd = &cobra.Command{
 		proxyConfs := map[string]config.ProxyConf{
 			cfg.ProxyName: cfg,
 		}
-		err = startService(proxyConfs, nil)
+		err = startService(clientCfg, proxyConfs, nil, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)

+ 2 - 2
cmd/frpc/sub/https.go

@@ -50,7 +50,7 @@ var httpsCmd = &cobra.Command{
 	Use:   "https",
 	Short: "Run frpc with a single https proxy",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		err := parseClientCommonCfg(CfgFileTypeCmd, "")
+		clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)
@@ -79,7 +79,7 @@ var httpsCmd = &cobra.Command{
 		proxyConfs := map[string]config.ProxyConf{
 			cfg.ProxyName: cfg,
 		}
-		err = startService(proxyConfs, nil)
+		err = startService(clientCfg, proxyConfs, nil, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)

+ 7 - 8
cmd/frpc/sub/reload.go

@@ -24,7 +24,6 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/fatedier/frp/g"
 	"github.com/fatedier/frp/models/config"
 )
 
@@ -42,13 +41,13 @@ var reloadCmd = &cobra.Command{
 			os.Exit(1)
 		}
 
-		err = parseClientCommonCfg(CfgFileTypeIni, iniContent)
+		clientCfg, err := parseClientCommonCfg(CfgFileTypeIni, iniContent)
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)
 		}
 
-		err = reload()
+		err = reload(clientCfg)
 		if err != nil {
 			fmt.Printf("frpc reload error: %v\n", err)
 			os.Exit(1)
@@ -58,19 +57,19 @@ var reloadCmd = &cobra.Command{
 	},
 }
 
-func reload() error {
-	if g.GlbClientCfg.AdminPort == 0 {
+func reload(clientCfg config.ClientCommonConf) error {
+	if clientCfg.AdminPort == 0 {
 		return fmt.Errorf("admin_port shoud be set if you want to use reload feature")
 	}
 
 	req, err := http.NewRequest("GET", "http://"+
-		g.GlbClientCfg.AdminAddr+":"+fmt.Sprintf("%d", g.GlbClientCfg.AdminPort)+"/api/reload", nil)
+		clientCfg.AdminAddr+":"+fmt.Sprintf("%d", clientCfg.AdminPort)+"/api/reload", nil)
 	if err != nil {
 		return err
 	}
 
-	authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(g.GlbClientCfg.AdminUser+":"+
-		g.GlbClientCfg.AdminPwd))
+	authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(clientCfg.AdminUser+":"+
+		clientCfg.AdminPwd))
 
 	req.Header.Add("Authorization", authStr)
 	resp, err := http.DefaultClient.Do(req)

+ 35 - 35
cmd/frpc/sub/root.go

@@ -28,7 +28,6 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/fatedier/frp/client"
-	"github.com/fatedier/frp/g"
 	"github.com/fatedier/frp/models/config"
 	"github.com/fatedier/frp/utils/log"
 	"github.com/fatedier/frp/utils/version"
@@ -114,60 +113,62 @@ func handleSignal(svr *client.Service) {
 	close(kcpDoneCh)
 }
 
-func parseClientCommonCfg(fileType int, content string) (err error) {
+func parseClientCommonCfg(fileType int, content string) (cfg config.ClientCommonConf, err error) {
 	if fileType == CfgFileTypeIni {
-		err = parseClientCommonCfgFromIni(content)
+		cfg, err = parseClientCommonCfgFromIni(content)
 	} else if fileType == CfgFileTypeCmd {
-		err = parseClientCommonCfgFromCmd()
+		cfg, err = parseClientCommonCfgFromCmd()
 	}
 	if err != nil {
 		return
 	}
 
-	err = g.GlbClientCfg.ClientCommonConf.Check()
+	err = cfg.Check()
 	if err != nil {
 		return
 	}
 	return
 }
 
-func parseClientCommonCfgFromIni(content string) (err error) {
-	cfg, err := config.UnmarshalClientConfFromIni(&g.GlbClientCfg.ClientCommonConf, content)
+func parseClientCommonCfgFromIni(content string) (config.ClientCommonConf, error) {
+	cfg, err := config.UnmarshalClientConfFromIni(content)
 	if err != nil {
-		return err
+		return config.ClientCommonConf{}, err
 	}
-	g.GlbClientCfg.ClientCommonConf = *cfg
-	return
+	return cfg, err
 }
 
-func parseClientCommonCfgFromCmd() (err error) {
+func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
+	cfg = config.GetDefaultClientConf()
+
 	strs := strings.Split(serverAddr, ":")
 	if len(strs) < 2 {
 		err = fmt.Errorf("invalid server_addr")
 		return
 	}
 	if strs[0] != "" {
-		g.GlbClientCfg.ServerAddr = strs[0]
+		cfg.ServerAddr = strs[0]
 	}
-	g.GlbClientCfg.ServerPort, err = strconv.Atoi(strs[1])
+	cfg.ServerPort, err = strconv.Atoi(strs[1])
 	if err != nil {
 		err = fmt.Errorf("invalid server_addr")
 		return
 	}
 
-	g.GlbClientCfg.User = user
-	g.GlbClientCfg.Protocol = protocol
-	g.GlbClientCfg.Token = token
-	g.GlbClientCfg.LogLevel = logLevel
-	g.GlbClientCfg.LogFile = logFile
-	g.GlbClientCfg.LogMaxDays = int64(logMaxDays)
+	cfg.User = user
+	cfg.Protocol = protocol
+	cfg.Token = token
+	cfg.LogLevel = logLevel
+	cfg.LogFile = logFile
+	cfg.LogMaxDays = int64(logMaxDays)
 	if logFile == "console" {
-		g.GlbClientCfg.LogWay = "console"
+		cfg.LogWay = "console"
 	} else {
-		g.GlbClientCfg.LogWay = "file"
+		cfg.LogWay = "file"
 	}
-	g.GlbClientCfg.DisableLogColor = disableLogColor
-	return nil
+	cfg.DisableLogColor = disableLogColor
+
+	return
 }
 
 func runClient(cfgFilePath string) (err error) {
@@ -176,28 +177,27 @@ func runClient(cfgFilePath string) (err error) {
 	if err != nil {
 		return
 	}
-	g.GlbClientCfg.CfgFile = cfgFilePath
 
-	err = parseClientCommonCfg(CfgFileTypeIni, content)
+	cfg, err := parseClientCommonCfg(CfgFileTypeIni, content)
 	if err != nil {
 		return
 	}
 
-	pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(g.GlbClientCfg.User, content, g.GlbClientCfg.Start)
+	pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(cfg.User, content, cfg.Start)
 	if err != nil {
 		return err
 	}
 
-	err = startService(pxyCfgs, visitorCfgs)
+	err = startService(cfg, pxyCfgs, visitorCfgs, cfgFilePath)
 	return
 }
 
-func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (err error) {
-	log.InitLog(g.GlbClientCfg.LogWay, g.GlbClientCfg.LogFile, g.GlbClientCfg.LogLevel,
-		g.GlbClientCfg.LogMaxDays, g.GlbClientCfg.DisableLogColor)
+func startService(cfg config.ClientCommonConf, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (err error) {
+	log.InitLog(cfg.LogWay, cfg.LogFile, cfg.LogLevel,
+		cfg.LogMaxDays, cfg.DisableLogColor)
 
-	if g.GlbClientCfg.DnsServer != "" {
-		s := g.GlbClientCfg.DnsServer
+	if cfg.DnsServer != "" {
+		s := cfg.DnsServer
 		if !strings.Contains(s, ":") {
 			s += ":53"
 		}
@@ -209,19 +209,19 @@ func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]co
 			},
 		}
 	}
-	svr, errRet := client.NewService(pxyCfgs, visitorCfgs)
+	svr, errRet := client.NewService(cfg, pxyCfgs, visitorCfgs, cfgFile)
 	if errRet != nil {
 		err = errRet
 		return
 	}
 
 	// Capture the exit signal if we use kcp.
-	if g.GlbClientCfg.Protocol == "kcp" {
+	if cfg.Protocol == "kcp" {
 		go handleSignal(svr)
 	}
 
 	err = svr.Run()
-	if g.GlbClientCfg.Protocol == "kcp" {
+	if cfg.Protocol == "kcp" {
 		<-kcpDoneCh
 	}
 	return

+ 7 - 8
cmd/frpc/sub/status.go

@@ -27,7 +27,6 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/fatedier/frp/client"
-	"github.com/fatedier/frp/g"
 	"github.com/fatedier/frp/models/config"
 )
 
@@ -45,13 +44,13 @@ var statusCmd = &cobra.Command{
 			os.Exit(1)
 		}
 
-		err = parseClientCommonCfg(CfgFileTypeIni, iniContent)
+		clientCfg, err := parseClientCommonCfg(CfgFileTypeIni, iniContent)
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)
 		}
 
-		err = status()
+		err = status(clientCfg)
 		if err != nil {
 			fmt.Printf("frpc get status error: %v\n", err)
 			os.Exit(1)
@@ -60,19 +59,19 @@ var statusCmd = &cobra.Command{
 	},
 }
 
-func status() error {
-	if g.GlbClientCfg.AdminPort == 0 {
+func status(clientCfg config.ClientCommonConf) error {
+	if clientCfg.AdminPort == 0 {
 		return fmt.Errorf("admin_port shoud be set if you want to get proxy status")
 	}
 
 	req, err := http.NewRequest("GET", "http://"+
-		g.GlbClientCfg.AdminAddr+":"+fmt.Sprintf("%d", g.GlbClientCfg.AdminPort)+"/api/status", nil)
+		clientCfg.AdminAddr+":"+fmt.Sprintf("%d", clientCfg.AdminPort)+"/api/status", nil)
 	if err != nil {
 		return err
 	}
 
-	authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(g.GlbClientCfg.AdminUser+":"+
-		g.GlbClientCfg.AdminPwd))
+	authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(clientCfg.AdminUser+":"+
+		clientCfg.AdminPwd))
 
 	req.Header.Add("Authorization", authStr)
 	resp, err := http.DefaultClient.Do(req)

+ 2 - 2
cmd/frpc/sub/stcp.go

@@ -52,7 +52,7 @@ var stcpCmd = &cobra.Command{
 	Use:   "stcp",
 	Short: "Run frpc with a single stcp proxy",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		err := parseClientCommonCfg(CfgFileTypeCmd, "")
+		clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)
@@ -104,7 +104,7 @@ var stcpCmd = &cobra.Command{
 			os.Exit(1)
 		}
 
-		err = startService(proxyConfs, visitorConfs)
+		err = startService(clientCfg, proxyConfs, visitorConfs, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)

+ 2 - 2
cmd/frpc/sub/tcp.go

@@ -48,7 +48,7 @@ var tcpCmd = &cobra.Command{
 	Use:   "tcp",
 	Short: "Run frpc with a single tcp proxy",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		err := parseClientCommonCfg(CfgFileTypeCmd, "")
+		clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)
@@ -76,7 +76,7 @@ var tcpCmd = &cobra.Command{
 		proxyConfs := map[string]config.ProxyConf{
 			cfg.ProxyName: cfg,
 		}
-		err = startService(proxyConfs, nil)
+		err = startService(clientCfg, proxyConfs, nil, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)

+ 2 - 2
cmd/frpc/sub/udp.go

@@ -48,7 +48,7 @@ var udpCmd = &cobra.Command{
 	Use:   "udp",
 	Short: "Run frpc with a single udp proxy",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		err := parseClientCommonCfg(CfgFileTypeCmd, "")
+		clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)
@@ -76,7 +76,7 @@ var udpCmd = &cobra.Command{
 		proxyConfs := map[string]config.ProxyConf{
 			cfg.ProxyName: cfg,
 		}
-		err = startService(proxyConfs, nil)
+		err = startService(clientCfg, proxyConfs, nil, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)

+ 2 - 2
cmd/frpc/sub/xtcp.go

@@ -52,7 +52,7 @@ var xtcpCmd = &cobra.Command{
 	Use:   "xtcp",
 	Short: "Run frpc with a single xtcp proxy",
 	RunE: func(cmd *cobra.Command, args []string) error {
-		err := parseClientCommonCfg(CfgFileTypeCmd, "")
+		clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)
@@ -104,7 +104,7 @@ var xtcpCmd = &cobra.Command{
 			os.Exit(1)
 		}
 
-		err = startService(proxyConfs, visitorConfs)
+		err = startService(clientCfg, proxyConfs, visitorConfs, "")
 		if err != nil {
 			fmt.Println(err)
 			os.Exit(1)

+ 0 - 22
g/g.go

@@ -1,22 +0,0 @@
-package g
-
-import (
-	"github.com/fatedier/frp/models/config"
-)
-
-var (
-	GlbClientCfg *ClientCfg
-)
-
-func init() {
-	GlbClientCfg = &ClientCfg{
-		ClientCommonConf: *config.GetDefaultClientConf(),
-	}
-}
-
-type ClientCfg struct {
-	config.ClientCommonConf
-
-	CfgFile       string
-	ServerUdpPort int // this is configured by login response from frps
-}

+ 5 - 8
models/config/client_common.go

@@ -51,8 +51,8 @@ type ClientCommonConf struct {
 	HeartBeatTimeout  int64               `json:"heartbeat_timeout"`
 }
 
-func GetDefaultClientConf() *ClientCommonConf {
-	return &ClientCommonConf{
+func GetDefaultClientConf() ClientCommonConf {
+	return ClientCommonConf{
 		ServerAddr:        "0.0.0.0",
 		ServerPort:        7000,
 		HttpProxy:         os.Getenv("http_proxy"),
@@ -80,16 +80,13 @@ func GetDefaultClientConf() *ClientCommonConf {
 	}
 }
 
-func UnmarshalClientConfFromIni(defaultCfg *ClientCommonConf, content string) (cfg *ClientCommonConf, err error) {
-	cfg = defaultCfg
-	if cfg == nil {
-		cfg = GetDefaultClientConf()
-	}
+func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error) {
+	cfg = GetDefaultClientConf()
 
 	conf, err := ini.Load(strings.NewReader(content))
 	if err != nil {
 		err = fmt.Errorf("parse ini conf file error: %v", err)
-		return nil, err
+		return ClientCommonConf{}, err
 	}
 
 	var (