| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- // Copyright 2025 The frp Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package group
- import (
- "context"
- "net"
- "sync"
- gerr "github.com/fatedier/golib/errors"
- "github.com/fatedier/frp/pkg/util/vhost"
- )
- type HTTPSGroupController struct {
- groups map[string]*HTTPSGroup
- httpsMuxer *vhost.HTTPSMuxer
- mu sync.Mutex
- }
- func NewHTTPSGroupController(httpsMuxer *vhost.HTTPSMuxer) *HTTPSGroupController {
- return &HTTPSGroupController{
- groups: make(map[string]*HTTPSGroup),
- httpsMuxer: httpsMuxer,
- }
- }
- func (ctl *HTTPSGroupController) Listen(
- ctx context.Context,
- group, groupKey string,
- routeConfig vhost.RouteConfig,
- ) (l net.Listener, err error) {
- indexKey := group
- ctl.mu.Lock()
- g, ok := ctl.groups[indexKey]
- if !ok {
- g = NewHTTPSGroup(ctl)
- ctl.groups[indexKey] = g
- }
- ctl.mu.Unlock()
- return g.Listen(ctx, group, groupKey, routeConfig)
- }
- func (ctl *HTTPSGroupController) RemoveGroup(group string) {
- ctl.mu.Lock()
- defer ctl.mu.Unlock()
- delete(ctl.groups, group)
- }
- type HTTPSGroup struct {
- group string
- groupKey string
- domain string
- acceptCh chan net.Conn
- httpsLn *vhost.Listener
- lns []*HTTPSGroupListener
- ctl *HTTPSGroupController
- mu sync.Mutex
- }
- func NewHTTPSGroup(ctl *HTTPSGroupController) *HTTPSGroup {
- return &HTTPSGroup{
- lns: make([]*HTTPSGroupListener, 0),
- ctl: ctl,
- acceptCh: make(chan net.Conn),
- }
- }
- func (g *HTTPSGroup) Listen(
- ctx context.Context,
- group, groupKey string,
- routeConfig vhost.RouteConfig,
- ) (ln *HTTPSGroupListener, err error) {
- g.mu.Lock()
- defer g.mu.Unlock()
- if len(g.lns) == 0 {
- // the first listener, listen on the real address
- httpsLn, errRet := g.ctl.httpsMuxer.Listen(ctx, &routeConfig)
- if errRet != nil {
- return nil, errRet
- }
- ln = newHTTPSGroupListener(group, g, httpsLn.Addr())
- g.group = group
- g.groupKey = groupKey
- g.domain = routeConfig.Domain
- g.httpsLn = httpsLn
- g.lns = append(g.lns, ln)
- go g.worker()
- } else {
- // route config in the same group must be equal
- if g.group != group || g.domain != routeConfig.Domain {
- return nil, ErrGroupParamsInvalid
- }
- if g.groupKey != groupKey {
- return nil, ErrGroupAuthFailed
- }
- ln = newHTTPSGroupListener(group, g, g.lns[0].Addr())
- g.lns = append(g.lns, ln)
- }
- return
- }
- func (g *HTTPSGroup) worker() {
- for {
- c, err := g.httpsLn.Accept()
- if err != nil {
- return
- }
- err = gerr.PanicToError(func() {
- g.acceptCh <- c
- })
- if err != nil {
- return
- }
- }
- }
- func (g *HTTPSGroup) Accept() <-chan net.Conn {
- return g.acceptCh
- }
- func (g *HTTPSGroup) CloseListener(ln *HTTPSGroupListener) {
- g.mu.Lock()
- defer g.mu.Unlock()
- for i, tmpLn := range g.lns {
- if tmpLn == ln {
- g.lns = append(g.lns[:i], g.lns[i+1:]...)
- break
- }
- }
- if len(g.lns) == 0 {
- close(g.acceptCh)
- if g.httpsLn != nil {
- g.httpsLn.Close()
- }
- g.ctl.RemoveGroup(g.group)
- }
- }
- type HTTPSGroupListener struct {
- groupName string
- group *HTTPSGroup
- addr net.Addr
- closeCh chan struct{}
- }
- func newHTTPSGroupListener(name string, group *HTTPSGroup, addr net.Addr) *HTTPSGroupListener {
- return &HTTPSGroupListener{
- groupName: name,
- group: group,
- addr: addr,
- closeCh: make(chan struct{}),
- }
- }
- func (ln *HTTPSGroupListener) Accept() (c net.Conn, err error) {
- var ok bool
- select {
- case <-ln.closeCh:
- return nil, ErrListenerClosed
- case c, ok = <-ln.group.Accept():
- if !ok {
- return nil, ErrListenerClosed
- }
- return c, nil
- }
- }
- func (ln *HTTPSGroupListener) Addr() net.Addr {
- return ln.addr
- }
- func (ln *HTTPSGroupListener) Close() (err error) {
- close(ln.closeCh)
- // remove self from HTTPSGroup
- ln.group.CloseListener(ln)
- return
- }
|