server.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package server
  2. import (
  3. "container/list"
  4. "sync"
  5. "github.com/fatedier/frp/models/consts"
  6. "github.com/fatedier/frp/utils/conn"
  7. "github.com/fatedier/frp/utils/log"
  8. )
  9. type ProxyServer struct {
  10. Name string
  11. Passwd string
  12. BindAddr string
  13. ListenPort int64
  14. Status int64
  15. CliConnChan chan *conn.Conn // get client conns from control goroutine
  16. listener *conn.Listener // accept new connection from remote users
  17. ctlMsgChan chan int64 // every time accept a new user conn, put "1" to the channel
  18. userConnList *list.List // store user conns
  19. mutex sync.Mutex
  20. }
  21. func (p *ProxyServer) Init() {
  22. p.Status = consts.Idle
  23. p.CliConnChan = make(chan *conn.Conn)
  24. p.ctlMsgChan = make(chan int64)
  25. p.userConnList = list.New()
  26. }
  27. func (p *ProxyServer) Lock() {
  28. p.mutex.Lock()
  29. }
  30. func (p *ProxyServer) Unlock() {
  31. p.mutex.Unlock()
  32. }
  33. // start listening for user conns
  34. func (p *ProxyServer) Start() (err error) {
  35. p.Init()
  36. p.listener, err = conn.Listen(p.BindAddr, p.ListenPort)
  37. if err != nil {
  38. return err
  39. }
  40. p.Status = consts.Working
  41. // start a goroutine for listener
  42. go func() {
  43. for {
  44. // block
  45. // if listener is closed, get nil
  46. c := p.listener.GetConn()
  47. if c == nil {
  48. log.Info("ProxyName [%s], listener is closed", p.Name)
  49. return
  50. }
  51. log.Debug("ProxyName [%s], get one new user conn [%s]", p.Name, c.GetRemoteAddr())
  52. // insert into list
  53. p.Lock()
  54. if p.Status != consts.Working {
  55. log.Debug("ProxyName [%s] is not working, new user conn close", p.Name)
  56. c.Close()
  57. p.Unlock()
  58. return
  59. }
  60. p.userConnList.PushBack(c)
  61. p.Unlock()
  62. // put msg to control conn
  63. p.ctlMsgChan <- 1
  64. }
  65. }()
  66. // start another goroutine for join two conns from client and user
  67. go func() {
  68. for {
  69. cliConn, ok := <-p.CliConnChan
  70. if !ok {
  71. return
  72. }
  73. p.Lock()
  74. element := p.userConnList.Front()
  75. var userConn *conn.Conn
  76. if element != nil {
  77. userConn = element.Value.(*conn.Conn)
  78. p.userConnList.Remove(element)
  79. } else {
  80. cliConn.Close()
  81. p.Unlock()
  82. continue
  83. }
  84. p.Unlock()
  85. // msg will transfer to another without modifying
  86. // l means local, r means remote
  87. log.Debug("Join two conns, (l[%s] r[%s]) (l[%s] r[%s])", cliConn.GetLocalAddr(), cliConn.GetRemoteAddr(),
  88. userConn.GetLocalAddr(), userConn.GetRemoteAddr())
  89. go conn.Join(cliConn, userConn)
  90. }
  91. }()
  92. return nil
  93. }
  94. func (p *ProxyServer) Close() {
  95. p.Lock()
  96. p.Status = consts.Idle
  97. p.listener.Close()
  98. close(p.ctlMsgChan)
  99. close(p.CliConnChan)
  100. p.userConnList = list.New()
  101. p.Unlock()
  102. }
  103. func (p *ProxyServer) WaitUserConn() (closeFlag bool) {
  104. closeFlag = false
  105. _, ok := <-p.ctlMsgChan
  106. if !ok {
  107. closeFlag = true
  108. }
  109. return
  110. }