server.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. Listener *conn.Listener // accept new connection from remote users
  16. CtlMsgChan chan int64 // every time accept a new user conn, put "1" to the channel
  17. StopBlockChan chan int64 // put any number to the channel, if you want to stop wait user conn
  18. CliConnChan chan *conn.Conn // get client conns from control goroutine
  19. UserConnList *list.List // store user conns
  20. Mutex sync.Mutex
  21. }
  22. func (p *ProxyServer) Init() {
  23. p.Status = consts.Idle
  24. p.CtlMsgChan = make(chan int64)
  25. p.StopBlockChan = make(chan int64)
  26. p.CliConnChan = make(chan *conn.Conn)
  27. p.UserConnList = list.New()
  28. }
  29. func (p *ProxyServer) Lock() {
  30. p.Mutex.Lock()
  31. }
  32. func (p *ProxyServer) Unlock() {
  33. p.Mutex.Unlock()
  34. }
  35. // start listening for user conns
  36. func (p *ProxyServer) Start() (err error) {
  37. p.Listener, err = conn.Listen(p.BindAddr, p.ListenPort)
  38. if err != nil {
  39. return err
  40. }
  41. p.Status = consts.Working
  42. // start a goroutine for listener
  43. go func() {
  44. for {
  45. // block
  46. c := p.Listener.GetConn()
  47. log.Debug("ProxyName [%s], get one new user conn [%s]", p.Name, c.GetRemoteAddr())
  48. // put to list
  49. p.Lock()
  50. if p.Status != consts.Working {
  51. log.Debug("ProxyName [%s] is not working, new user conn close", p.Name)
  52. c.Close()
  53. p.Unlock()
  54. return
  55. }
  56. p.UserConnList.PushBack(c)
  57. p.Unlock()
  58. // put msg to control conn
  59. p.CtlMsgChan <- 1
  60. }
  61. }()
  62. // start another goroutine for join two conns from client and user
  63. go func() {
  64. for {
  65. cliConn := <-p.CliConnChan
  66. p.Lock()
  67. element := p.UserConnList.Front()
  68. var userConn *conn.Conn
  69. if element != nil {
  70. userConn = element.Value.(*conn.Conn)
  71. p.UserConnList.Remove(element)
  72. } else {
  73. cliConn.Close()
  74. p.Unlock()
  75. continue
  76. }
  77. p.Unlock()
  78. // msg will transfer to another without modifying
  79. // l means local, r means remote
  80. log.Debug("Join two conns, (l[%s] r[%s]) (l[%s] r[%s])", cliConn.GetLocalAddr(), cliConn.GetRemoteAddr(),
  81. userConn.GetLocalAddr(), userConn.GetRemoteAddr())
  82. go conn.Join(cliConn, userConn)
  83. }
  84. }()
  85. return nil
  86. }
  87. func (p *ProxyServer) Close() {
  88. p.Lock()
  89. p.Status = consts.Idle
  90. p.CtlMsgChan = make(chan int64)
  91. p.CliConnChan = make(chan *conn.Conn)
  92. p.UserConnList = list.New()
  93. p.Unlock()
  94. }
  95. func (p *ProxyServer) WaitUserConn() (res int64, isStop bool) {
  96. select {
  97. case res = <-p.CtlMsgChan:
  98. return res, false
  99. case <-p.StopBlockChan:
  100. return 0, true
  101. }
  102. }
  103. func (p *ProxyServer) StopWaitUserConn() {
  104. p.StopBlockChan <- 1
  105. }