http.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package group
  2. import (
  3. "fmt"
  4. "net"
  5. "sync"
  6. "sync/atomic"
  7. "github.com/fatedier/frp/pkg/util/vhost"
  8. )
  9. type HTTPGroupController struct {
  10. groups map[string]*HTTPGroup
  11. vhostRouter *vhost.Routers
  12. mu sync.Mutex
  13. }
  14. func NewHTTPGroupController(vhostRouter *vhost.Routers) *HTTPGroupController {
  15. return &HTTPGroupController{
  16. groups: make(map[string]*HTTPGroup),
  17. vhostRouter: vhostRouter,
  18. }
  19. }
  20. func (ctl *HTTPGroupController) Register(proxyName, group, groupKey string,
  21. routeConfig vhost.RouteConfig) (err error) {
  22. indexKey := httpGroupIndex(group, routeConfig.Domain, routeConfig.Location)
  23. ctl.mu.Lock()
  24. g, ok := ctl.groups[indexKey]
  25. if !ok {
  26. g = NewHTTPGroup(ctl)
  27. ctl.groups[indexKey] = g
  28. }
  29. ctl.mu.Unlock()
  30. return g.Register(proxyName, group, groupKey, routeConfig)
  31. }
  32. func (ctl *HTTPGroupController) UnRegister(proxyName, group, domain, location string) {
  33. indexKey := httpGroupIndex(group, domain, location)
  34. ctl.mu.Lock()
  35. defer ctl.mu.Unlock()
  36. g, ok := ctl.groups[indexKey]
  37. if !ok {
  38. return
  39. }
  40. isEmpty := g.UnRegister(proxyName)
  41. if isEmpty {
  42. delete(ctl.groups, indexKey)
  43. }
  44. }
  45. type HTTPGroup struct {
  46. group string
  47. groupKey string
  48. domain string
  49. location string
  50. createFuncs map[string]vhost.CreateConnFunc
  51. pxyNames []string
  52. index uint64
  53. ctl *HTTPGroupController
  54. mu sync.RWMutex
  55. }
  56. func NewHTTPGroup(ctl *HTTPGroupController) *HTTPGroup {
  57. return &HTTPGroup{
  58. createFuncs: make(map[string]vhost.CreateConnFunc),
  59. pxyNames: make([]string, 0),
  60. ctl: ctl,
  61. }
  62. }
  63. func (g *HTTPGroup) Register(proxyName, group, groupKey string,
  64. routeConfig vhost.RouteConfig) (err error) {
  65. g.mu.Lock()
  66. defer g.mu.Unlock()
  67. if len(g.createFuncs) == 0 {
  68. // the first proxy in this group
  69. tmp := routeConfig // copy object
  70. tmp.CreateConnFn = g.createConn
  71. err = g.ctl.vhostRouter.Add(routeConfig.Domain, routeConfig.Location, &tmp)
  72. if err != nil {
  73. return
  74. }
  75. g.group = group
  76. g.groupKey = groupKey
  77. g.domain = routeConfig.Domain
  78. g.location = routeConfig.Location
  79. } else {
  80. if g.group != group || g.domain != routeConfig.Domain || g.location != routeConfig.Location {
  81. err = ErrGroupParamsInvalid
  82. return
  83. }
  84. if g.groupKey != groupKey {
  85. err = ErrGroupAuthFailed
  86. return
  87. }
  88. }
  89. if _, ok := g.createFuncs[proxyName]; ok {
  90. err = ErrProxyRepeated
  91. return
  92. }
  93. g.createFuncs[proxyName] = routeConfig.CreateConnFn
  94. g.pxyNames = append(g.pxyNames, proxyName)
  95. return nil
  96. }
  97. func (g *HTTPGroup) UnRegister(proxyName string) (isEmpty bool) {
  98. g.mu.Lock()
  99. defer g.mu.Unlock()
  100. delete(g.createFuncs, proxyName)
  101. for i, name := range g.pxyNames {
  102. if name == proxyName {
  103. g.pxyNames = append(g.pxyNames[:i], g.pxyNames[i+1:]...)
  104. break
  105. }
  106. }
  107. if len(g.createFuncs) == 0 {
  108. isEmpty = true
  109. g.ctl.vhostRouter.Del(g.domain, g.location)
  110. }
  111. return
  112. }
  113. func (g *HTTPGroup) createConn(remoteAddr string) (net.Conn, error) {
  114. var f vhost.CreateConnFunc
  115. newIndex := atomic.AddUint64(&g.index, 1)
  116. g.mu.RLock()
  117. group := g.group
  118. domain := g.domain
  119. location := g.location
  120. if len(g.pxyNames) > 0 {
  121. name := g.pxyNames[int(newIndex)%len(g.pxyNames)]
  122. f, _ = g.createFuncs[name]
  123. }
  124. g.mu.RUnlock()
  125. if f == nil {
  126. return nil, fmt.Errorf("no CreateConnFunc for http group [%s], domain [%s], location [%s]", group, domain, location)
  127. }
  128. return f(remoteAddr)
  129. }
  130. func httpGroupIndex(group, domain, location string) string {
  131. return fmt.Sprintf("%s_%s_%s", group, domain, location)
  132. }