virtual_net.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright 2025 The frp Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //go:build !frps
  15. package client
  16. import (
  17. "context"
  18. "io"
  19. "sync"
  20. v1 "github.com/fatedier/frp/pkg/config/v1"
  21. )
  22. func init() {
  23. Register(v1.PluginVirtualNet, NewVirtualNetPlugin)
  24. }
  25. type VirtualNetPlugin struct {
  26. pluginCtx PluginContext
  27. opts *v1.VirtualNetPluginOptions
  28. mu sync.Mutex
  29. conns map[io.ReadWriteCloser]struct{}
  30. }
  31. func NewVirtualNetPlugin(pluginCtx PluginContext, options v1.ClientPluginOptions) (Plugin, error) {
  32. opts := options.(*v1.VirtualNetPluginOptions)
  33. p := &VirtualNetPlugin{
  34. pluginCtx: pluginCtx,
  35. opts: opts,
  36. }
  37. return p, nil
  38. }
  39. func (p *VirtualNetPlugin) Handle(ctx context.Context, connInfo *ConnectionInfo) {
  40. // Verify if virtual network controller is available
  41. if p.pluginCtx.VnetController == nil {
  42. return
  43. }
  44. // Add the connection before starting the read loop to avoid race condition
  45. // where RemoveConn might be called before the connection is added.
  46. p.mu.Lock()
  47. if p.conns == nil {
  48. p.conns = make(map[io.ReadWriteCloser]struct{})
  49. }
  50. p.conns[connInfo.Conn] = struct{}{}
  51. p.mu.Unlock()
  52. // Register the connection with the controller and pass the cleanup function
  53. p.pluginCtx.VnetController.StartServerConnReadLoop(ctx, connInfo.Conn, func() {
  54. p.RemoveConn(connInfo.Conn)
  55. })
  56. }
  57. func (p *VirtualNetPlugin) RemoveConn(conn io.ReadWriteCloser) {
  58. p.mu.Lock()
  59. defer p.mu.Unlock()
  60. // Check if the map exists, as Close might have set it to nil concurrently
  61. if p.conns != nil {
  62. delete(p.conns, conn)
  63. }
  64. }
  65. func (p *VirtualNetPlugin) Name() string {
  66. return v1.PluginVirtualNet
  67. }
  68. func (p *VirtualNetPlugin) Close() error {
  69. p.mu.Lock()
  70. defer p.mu.Unlock()
  71. // Close any remaining connections
  72. for conn := range p.conns {
  73. _ = conn.Close()
  74. }
  75. p.conns = nil
  76. return nil
  77. }