mirror of
https://github.com/fatedier/frp.git
synced 2026-04-28 03:49:09 +08:00
protocol: add v2 wire protocol with binary framing and capability negotiation (#5294)
This commit is contained in:
@@ -44,7 +44,26 @@ func RegisterProxyFactory(proxyConfType reflect.Type, factory func(*BaseProxy) P
|
||||
proxyFactoryRegistry[proxyConfType] = factory
|
||||
}
|
||||
|
||||
type GetWorkConnFn func() (net.Conn, error)
|
||||
type WorkConn struct {
|
||||
conn *msg.Conn
|
||||
}
|
||||
|
||||
func NewWorkConn(conn *msg.Conn) *WorkConn {
|
||||
return &WorkConn{conn: conn}
|
||||
}
|
||||
|
||||
func (c *WorkConn) Start(m *msg.StartWorkConn) (net.Conn, error) {
|
||||
if err := c.conn.WriteMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.conn, nil
|
||||
}
|
||||
|
||||
func (c *WorkConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
type GetWorkConnFn func() (*WorkConn, error)
|
||||
|
||||
type Proxy interface {
|
||||
Context() context.Context
|
||||
@@ -125,13 +144,13 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
|
||||
xl := xlog.FromContextSafe(pxy.ctx)
|
||||
// try all connections from the pool
|
||||
for i := 0; i < pxy.poolCount+1; i++ {
|
||||
if workConn, err = pxy.getWorkConnFn(); err != nil {
|
||||
var pxyWorkConn *WorkConn
|
||||
if pxyWorkConn, err = pxy.getWorkConnFn(); err != nil {
|
||||
xl.Warnf("failed to get work connection: %v", err)
|
||||
return
|
||||
}
|
||||
xl.Debugf("get a new work connection: [%s]", workConn.RemoteAddr().String())
|
||||
xl.Debugf("get a new work connection: [%s]", pxyWorkConn.conn.RemoteAddr().String())
|
||||
xl.Spawn().AppendPrefix(pxy.GetName())
|
||||
workConn = netpkg.NewContextConn(pxy.ctx, workConn)
|
||||
|
||||
var (
|
||||
srcAddr string
|
||||
@@ -150,7 +169,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
|
||||
dstAddr, dstPortStr, _ = net.SplitHostPort(dst.String())
|
||||
dstPort, _ = strconv.ParseUint(dstPortStr, 10, 16)
|
||||
}
|
||||
err = msg.WriteMsg(workConn, &msg.StartWorkConn{
|
||||
workConn, err = pxyWorkConn.Start(&msg.StartWorkConn{
|
||||
ProxyName: pxy.GetName(),
|
||||
SrcAddr: srcAddr,
|
||||
SrcPort: uint16(srcPort),
|
||||
@@ -160,9 +179,10 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
|
||||
})
|
||||
if err != nil {
|
||||
xl.Warnf("failed to send message to work connection from pool: %v, times: %d", err, i)
|
||||
workConn.Close()
|
||||
pxyWorkConn.Close()
|
||||
workConn = nil
|
||||
} else {
|
||||
workConn = netpkg.NewContextConn(pxy.ctx, workConn)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
53
server/proxy/proxy_test.go
Normal file
53
server/proxy/proxy_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2026 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 proxy
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/fatedier/frp/pkg/msg"
|
||||
)
|
||||
|
||||
func TestWorkConnStartWritesStartWorkConn(t *testing.T) {
|
||||
client, server := net.Pipe()
|
||||
defer client.Close()
|
||||
defer server.Close()
|
||||
|
||||
serverMsgConn := msg.NewConn(server, msg.NewV2ReadWriter(server))
|
||||
clientMsgConn := msg.NewConn(client, msg.NewV2ReadWriter(client))
|
||||
workConn := NewWorkConn(serverMsgConn)
|
||||
|
||||
in := &msg.StartWorkConn{ProxyName: "tcp", SrcAddr: "127.0.0.1", SrcPort: 1234}
|
||||
type startResult struct {
|
||||
conn net.Conn
|
||||
err error
|
||||
}
|
||||
resultCh := make(chan startResult, 1)
|
||||
go func() {
|
||||
conn, err := workConn.Start(in)
|
||||
resultCh <- startResult{conn: conn, err: err}
|
||||
}()
|
||||
|
||||
out, err := clientMsgConn.ReadMsg()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, in, out)
|
||||
|
||||
result := <-resultCh
|
||||
require.NoError(t, result.err)
|
||||
require.Same(t, serverMsgConn, result.conn)
|
||||
}
|
||||
Reference in New Issue
Block a user