123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- package client
- import (
- "fmt"
- "sync"
- "github.com/fatedier/frp/models/config"
- "github.com/fatedier/frp/models/msg"
- "github.com/fatedier/frp/utils/errors"
- "github.com/fatedier/frp/utils/log"
- frpNet "github.com/fatedier/frp/utils/net"
- )
- const (
- ProxyStatusNew = "new"
- ProxyStatusStartErr = "start error"
- ProxyStatusWaitStart = "wait start"
- ProxyStatusRunning = "running"
- ProxyStatusClosed = "closed"
- )
- type ProxyManager struct {
- ctl *Control
- proxies map[string]*ProxyWrapper
- visitorCfgs map[string]config.ProxyConf
- visitors map[string]Visitor
- sendCh chan (msg.Message)
- closed bool
- mu sync.RWMutex
- log.Logger
- }
- type ProxyWrapper struct {
- Name string
- Type string
- Status string
- Err string
- Cfg config.ProxyConf
- RemoteAddr string
- pxy Proxy
- mu sync.RWMutex
- }
- type ProxyStatus struct {
- Name string `json:"name"`
- Type string `json:"type"`
- Status string `json:"status"`
- Err string `json:"err"`
- Cfg config.ProxyConf `json:"cfg"`
- // Got from server.
- RemoteAddr string `json:"remote_addr"`
- }
- func NewProxyWrapper(cfg config.ProxyConf) *ProxyWrapper {
- return &ProxyWrapper{
- Name: cfg.GetName(),
- Type: cfg.GetType(),
- Status: ProxyStatusNew,
- Cfg: cfg,
- pxy: nil,
- }
- }
- func (pw *ProxyWrapper) GetStatusStr() string {
- pw.mu.RLock()
- defer pw.mu.RUnlock()
- return pw.Status
- }
- func (pw *ProxyWrapper) GetStatus() *ProxyStatus {
- pw.mu.RLock()
- defer pw.mu.RUnlock()
- ps := &ProxyStatus{
- Name: pw.Name,
- Type: pw.Type,
- Status: pw.Status,
- Err: pw.Err,
- Cfg: pw.Cfg,
- RemoteAddr: pw.RemoteAddr,
- }
- return ps
- }
- func (pw *ProxyWrapper) WaitStart() {
- pw.mu.Lock()
- defer pw.mu.Unlock()
- pw.Status = ProxyStatusWaitStart
- }
- func (pw *ProxyWrapper) Start(remoteAddr string, serverRespErr string) error {
- if pw.pxy != nil {
- pw.pxy.Close()
- pw.pxy = nil
- }
- if serverRespErr != "" {
- pw.mu.Lock()
- pw.Status = ProxyStatusStartErr
- pw.RemoteAddr = remoteAddr
- pw.Err = serverRespErr
- pw.mu.Unlock()
- return fmt.Errorf(serverRespErr)
- }
- pxy := NewProxy(pw.Cfg)
- pw.mu.Lock()
- defer pw.mu.Unlock()
- pw.RemoteAddr = remoteAddr
- if err := pxy.Run(); err != nil {
- pw.Status = ProxyStatusStartErr
- pw.Err = err.Error()
- return err
- }
- pw.Status = ProxyStatusRunning
- pw.Err = ""
- pw.pxy = pxy
- return nil
- }
- func (pw *ProxyWrapper) InWorkConn(workConn frpNet.Conn) {
- pw.mu.RLock()
- pxy := pw.pxy
- pw.mu.RUnlock()
- if pxy != nil {
- workConn.Debug("start a new work connection, localAddr: %s remoteAddr: %s", workConn.LocalAddr().String(), workConn.RemoteAddr().String())
- go pxy.InWorkConn(workConn)
- } else {
- workConn.Close()
- }
- }
- func (pw *ProxyWrapper) Close() {
- pw.mu.Lock()
- defer pw.mu.Unlock()
- if pw.pxy != nil {
- pw.pxy.Close()
- pw.pxy = nil
- }
- pw.Status = ProxyStatusClosed
- }
- func NewProxyManager(ctl *Control, msgSendCh chan (msg.Message), logPrefix string) *ProxyManager {
- return &ProxyManager{
- ctl: ctl,
- proxies: make(map[string]*ProxyWrapper),
- visitorCfgs: make(map[string]config.ProxyConf),
- visitors: make(map[string]Visitor),
- sendCh: msgSendCh,
- closed: false,
- Logger: log.NewPrefixLogger(logPrefix),
- }
- }
- func (pm *ProxyManager) Reset(msgSendCh chan (msg.Message), logPrefix string) {
- pm.mu.Lock()
- defer pm.mu.Unlock()
- pm.closed = false
- pm.sendCh = msgSendCh
- pm.ClearLogPrefix()
- pm.AddLogPrefix(logPrefix)
- }
- // Must hold the lock before calling this function.
- func (pm *ProxyManager) sendMsg(m msg.Message) error {
- err := errors.PanicToError(func() {
- pm.sendCh <- m
- })
- if err != nil {
- pm.closed = true
- }
- return err
- }
- func (pm *ProxyManager) StartProxy(name string, remoteAddr string, serverRespErr string) error {
- pm.mu.Lock()
- defer pm.mu.Unlock()
- if pm.closed {
- return fmt.Errorf("ProxyManager is closed now")
- }
- pxy, ok := pm.proxies[name]
- if !ok {
- return fmt.Errorf("no proxy found")
- }
- if err := pxy.Start(remoteAddr, serverRespErr); err != nil {
- errRet := err
- err = pm.sendMsg(&msg.CloseProxy{
- ProxyName: name,
- })
- if err != nil {
- errRet = fmt.Errorf("send CloseProxy message error")
- }
- return errRet
- }
- return nil
- }
- func (pm *ProxyManager) CloseProxies() {
- pm.mu.RLock()
- defer pm.mu.RUnlock()
- for _, pxy := range pm.proxies {
- pxy.Close()
- }
- }
- // pxyStatus: check and start proxies in which status
- func (pm *ProxyManager) CheckAndStartProxy(pxyStatus []string) {
- pm.mu.RLock()
- defer pm.mu.RUnlock()
- if pm.closed {
- pm.Warn("CheckAndStartProxy error: ProxyManager is closed now")
- return
- }
- for _, pxy := range pm.proxies {
- status := pxy.GetStatusStr()
- for _, s := range pxyStatus {
- if status == s {
- var newProxyMsg msg.NewProxy
- pxy.Cfg.UnMarshalToMsg(&newProxyMsg)
- err := pm.sendMsg(&newProxyMsg)
- if err != nil {
- pm.Warn("[%s] proxy send NewProxy message error")
- return
- }
- pxy.WaitStart()
- break
- }
- }
- }
- for _, cfg := range pm.visitorCfgs {
- if _, exist := pm.visitors[cfg.GetName()]; !exist {
- pm.Info("try to start visitor [%s]", cfg.GetName())
- visitor := NewVisitor(pm.ctl, cfg)
- err := visitor.Run()
- if err != nil {
- visitor.Warn("start error: %v", err)
- continue
- }
- pm.visitors[cfg.GetName()] = visitor
- visitor.Info("start visitor success")
- }
- }
- }
- func (pm *ProxyManager) Reload(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.ProxyConf, startNow bool) error {
- pm.mu.Lock()
- defer func() {
- pm.mu.Unlock()
- if startNow {
- go pm.CheckAndStartProxy([]string{ProxyStatusNew})
- }
- }()
- if pm.closed {
- err := fmt.Errorf("Reload error: ProxyManager is closed now")
- pm.Warn(err.Error())
- return err
- }
- delPxyNames := make([]string, 0)
- for name, pxy := range pm.proxies {
- del := false
- cfg, ok := pxyCfgs[name]
- if !ok {
- del = true
- } else {
- if !pxy.Cfg.Compare(cfg) {
- del = true
- }
- }
- if del {
- delPxyNames = append(delPxyNames, name)
- delete(pm.proxies, name)
- pxy.Close()
- err := pm.sendMsg(&msg.CloseProxy{
- ProxyName: name,
- })
- if err != nil {
- err = fmt.Errorf("Reload error: ProxyManager is closed now")
- pm.Warn(err.Error())
- return err
- }
- }
- }
- pm.Info("proxy removed: %v", delPxyNames)
- addPxyNames := make([]string, 0)
- for name, cfg := range pxyCfgs {
- if _, ok := pm.proxies[name]; !ok {
- pxy := NewProxyWrapper(cfg)
- pm.proxies[name] = pxy
- addPxyNames = append(addPxyNames, name)
- }
- }
- pm.Info("proxy added: %v", addPxyNames)
- delVisitorName := make([]string, 0)
- for name, oldVisitorCfg := range pm.visitorCfgs {
- del := false
- cfg, ok := visitorCfgs[name]
- if !ok {
- del = true
- } else {
- if !oldVisitorCfg.Compare(cfg) {
- del = true
- }
- }
- if del {
- delVisitorName = append(delVisitorName, name)
- delete(pm.visitorCfgs, name)
- if visitor, ok := pm.visitors[name]; ok {
- visitor.Close()
- }
- delete(pm.visitors, name)
- }
- }
- pm.Info("visitor removed: %v", delVisitorName)
- addVisitorName := make([]string, 0)
- for name, visitorCfg := range visitorCfgs {
- if _, ok := pm.visitorCfgs[name]; !ok {
- pm.visitorCfgs[name] = visitorCfg
- addVisitorName = append(addVisitorName, name)
- }
- }
- pm.Info("visitor added: %v", addVisitorName)
- return nil
- }
- func (pm *ProxyManager) HandleWorkConn(name string, workConn frpNet.Conn) {
- pm.mu.RLock()
- pw, ok := pm.proxies[name]
- pm.mu.RUnlock()
- if ok {
- pw.InWorkConn(workConn)
- } else {
- workConn.Close()
- }
- }
- func (pm *ProxyManager) GetAllProxyStatus() []*ProxyStatus {
- ps := make([]*ProxyStatus, 0)
- pm.mu.RLock()
- defer pm.mu.RUnlock()
- for _, pxy := range pm.proxies {
- ps = append(ps, pxy.GetStatus())
- }
- return ps
- }
|