From d320d7c030097fbceeea80ab7b6808d3355e43cf Mon Sep 17 00:00:00 2001 From: haidy Date: Sat, 3 Aug 2019 21:25:48 +0800 Subject: [PATCH] frp client --- client/control.go | 4 +++ client/service.go | 41 +++++++++++++++++++++++++----- cmd/frp/frpc.go | 56 +++++++++++++++++++++++++++++++++++++++++ cmd/frpc/sub/root.go | 59 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 cmd/frp/frpc.go diff --git a/client/control.go b/client/control.go index 1afeec34..a23af4d8 100644 --- a/client/control.go +++ b/client/control.go @@ -71,6 +71,7 @@ type Control struct { mu sync.RWMutex log.Logger + ProxyFunc func(err error) } func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) *Control { @@ -139,6 +140,9 @@ func (ctl *Control) HandleNewProxyResp(inMsg *msg.NewProxyResp) { err := ctl.pm.StartProxy(inMsg.ProxyName, inMsg.RemoteAddr, inMsg.Error) if err != nil { ctl.Warn("[%s] start error: %v", inMsg.ProxyName, err) + if ctl.ProxyFunc != nil { + ctl.ProxyFunc(err) + } } else { ctl.Info("[%s] start proxy success", inMsg.ProxyName) } diff --git a/client/service.go b/client/service.go index f0fea07e..87037538 100644 --- a/client/service.go +++ b/client/service.go @@ -35,6 +35,10 @@ import ( fmux "github.com/hashicorp/yamux" ) +type ServiceClosedListener interface { + OnClosed(msg string) +} + type Service struct { // uniq id got from frps, attach it in loginMsg runId string @@ -50,7 +54,20 @@ type Service struct { exit uint32 // 0 means not exit closedCh chan bool - closed bool + closed bool + ReConnectByCount bool + reConnectCount int + onClosedListener ServiceClosedListener +} + +func (svr *Service) SetProxyFailedFunc(proxyFailedFunc func(err error)) { + if svr.ctl != nil { + svr.ctl.ProxyFunc = proxyFailedFunc + } +} + +func (svr *Service) SetOnCloseListener(listener ServiceClosedListener) { + svr.onClosedListener = listener } func NewService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (svr *Service, err error) { @@ -62,11 +79,12 @@ func NewService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]conf } svr = &Service{ - pxyCfgs: pxyCfgs, - visitorCfgs: visitorCfgs, - exit: 0, - closedCh: make(chan bool), - closed: true, + pxyCfgs: pxyCfgs, + visitorCfgs: visitorCfgs, + exit: 0, + closedCh: make(chan bool), + closed: true, + reConnectCount: 0, } return } @@ -120,6 +138,10 @@ func (svr *Service) Run(cmd bool) error { go func() { svr.closed = <-svr.closedCh log.Info("svr closed") + + if svr.onClosedListener != nil { + svr.onClosedListener.OnClosed("") + } }() } return nil @@ -145,6 +167,13 @@ func (svr *Service) keepControllerWorking() { if delayTime > maxDelayTime { delayTime = maxDelayTime } + if svr.ReConnectByCount { + svr.reConnectCount++ + if svr.reConnectCount == 3 { + svr.Close() + return + } + } continue } // reconnect success, init delayTime diff --git a/cmd/frp/frpc.go b/cmd/frp/frpc.go new file mode 100644 index 00000000..3de3565c --- /dev/null +++ b/cmd/frp/frpc.go @@ -0,0 +1,56 @@ +package frp + +import ( + "github.com/fatedier/frp/client" + "github.com/fatedier/frp/cmd/frpc/sub" + "log" +) + +type FRPCService struct { + *client.Service + l FRPCClosedListener + proxyFailedListener ProxyFailedListener +} + +type FRPCClosedListener interface { + OnClosed(msg string) +} + +type ProxyFailedListener interface { + OnProxyFailed() +} + +func (frp *FRPCService) OnClosed(msg string) { + log.Printf("OnClosed() l = %v", frp.l) + if frp.l != nil { + frp.l.OnClosed(msg) + } +} + +func (frp *FRPCService) SetFRPCCloseListener(listener FRPCClosedListener) { + frp.l = listener + frp.SetOnCloseListener(frp) +} + +func (frp *FRPCService) onProxyFailed(err error) { + if frp.proxyFailedListener != nil { + frp.proxyFailedListener.OnProxyFailed() + } +} + +func (frp *FRPCService) SetProxyFailedListener(listener ProxyFailedListener) { + frp.proxyFailedListener = listener + frp.SetProxyFailedFunc(frp.onProxyFailed) +} + +func (frp *FRPCService) SetReConnectByCount(reConnectByCount bool) { + frp.ReConnectByCount = reConnectByCount +} + +func NewFrpcServiceWithPath(path string) (*FRPCService, error) { + svr, err := sub.NewService(path) + if err != nil { + return nil, err + } + return &FRPCService{Service: svr}, nil +} diff --git a/cmd/frpc/sub/root.go b/cmd/frpc/sub/root.go index 8dd12aad..5d8092f4 100644 --- a/cmd/frpc/sub/root.go +++ b/cmd/frpc/sub/root.go @@ -117,6 +117,12 @@ func RunFrpc(cfgFilePath string) (err error) { return runClient(cfgFilePath) } +func NewService(cfgFilePath string) (ser *client.Service, err error) { + cmd = false + crypto.DefaultSalt = "frp" + return returnClient(cfgFilePath, false) +} + func StopFrp() (err error) { if service == nil { return fmt.Errorf("frp not start") @@ -214,8 +220,28 @@ func runClient(cfgFilePath string) (err error) { return err } - err = startService(pxyCfgs, visitorCfgs) - return + return startService(pxyCfgs, visitorCfgs) +} + +func returnClient(cfgFilePath string, run bool) (svr *client.Service, err error) { + var content string + content, err = config.GetRenderedConfFromFile(cfgFilePath) + if err != nil { + return + } + g.GlbClientCfg.CfgFile = cfgFilePath + + err = parseClientCommonCfg(CfgFileTypeIni, content) + if err != nil { + return + } + + pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(g.GlbClientCfg.User, content, g.GlbClientCfg.Start) + if err != nil { + return nil, err + } + + return returnService(pxyCfgs, visitorCfgs) } func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (err error) { @@ -251,3 +277,32 @@ func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]co } return } + +func returnService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (svr *client.Service, err error) { + log.InitLog(g.GlbClientCfg.LogWay, g.GlbClientCfg.LogFile, g.GlbClientCfg.LogLevel, g.GlbClientCfg.LogMaxDays) + if g.GlbClientCfg.DnsServer != "" { + s := g.GlbClientCfg.DnsServer + if !strings.Contains(s, ":") { + s += ":53" + } + // Change default dns server for frpc + net.DefaultResolver = &net.Resolver{ + PreferGo: true, + Dial: func(ctx context.Context, network, address string) (net.Conn, error) { + return net.Dial("udp", s) + }, + } + } + svr, errRet := client.NewService(pxyCfgs, visitorCfgs) + if errRet != nil { + err = errRet + return + } + + // Capture the exit signal if we use kcp. + if g.GlbClientCfg.Protocol == "kcp" { + go handleSignal(svr) + } + + return svr, err +}