mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-09-26 23:05:55 +08:00
feat: add port map to webrtc
This commit is contained in:
133
pkg/port.go
133
pkg/port.go
@@ -13,6 +13,7 @@ type (
|
||||
Port struct {
|
||||
Protocol string
|
||||
Ports [2]int
|
||||
Map [2]int // 映射端口范围,通常用于 NAT 或端口转发
|
||||
}
|
||||
IPort interface {
|
||||
IsTCP() bool
|
||||
@@ -22,10 +23,23 @@ type (
|
||||
)
|
||||
|
||||
func (p Port) String() string {
|
||||
var result string
|
||||
if p.Ports[0] == p.Ports[1] {
|
||||
return p.Protocol + ":" + strconv.Itoa(p.Ports[0])
|
||||
result = p.Protocol + ":" + strconv.Itoa(p.Ports[0])
|
||||
} else {
|
||||
result = p.Protocol + ":" + strconv.Itoa(p.Ports[0]) + "-" + strconv.Itoa(p.Ports[1])
|
||||
}
|
||||
return p.Protocol + ":" + strconv.Itoa(p.Ports[0]) + "-" + strconv.Itoa(p.Ports[1])
|
||||
|
||||
// 如果有端口映射,添加映射信息
|
||||
if p.HasMapping() {
|
||||
if p.Map[0] == p.Map[1] {
|
||||
result += ":" + strconv.Itoa(p.Map[0])
|
||||
} else {
|
||||
result += ":" + strconv.Itoa(p.Map[0]) + "-" + strconv.Itoa(p.Map[1])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (p Port) IsTCP() bool {
|
||||
@@ -40,6 +54,36 @@ func (p Port) IsRange() bool {
|
||||
return p.Ports[0] != p.Ports[1]
|
||||
}
|
||||
|
||||
func (p Port) HasMapping() bool {
|
||||
return p.Map[0] > 0 || p.Map[1] > 0
|
||||
}
|
||||
|
||||
func (p Port) IsRangeMapping() bool {
|
||||
return p.HasMapping() && p.Map[0] != p.Map[1]
|
||||
}
|
||||
|
||||
// ParsePort2 解析端口配置字符串并返回对应的端口类型实例
|
||||
// 根据协议类型和端口范围返回不同的类型:
|
||||
// - TCP单端口:返回 TCPPort
|
||||
// - TCP端口范围:返回 TCPRangePort
|
||||
// - UDP单端口:返回 UDPPort
|
||||
// - UDP端口范围:返回 UDPRangePort
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// conf - 端口配置字符串,格式:protocol:port 或 protocol:port1-port2
|
||||
//
|
||||
// 返回值:
|
||||
//
|
||||
// ret - 端口实例 (TCPPort/UDPPort/TCPRangePort/UDPRangePort)
|
||||
// err - 解析错误
|
||||
//
|
||||
// 示例:
|
||||
//
|
||||
// ParsePort2("tcp:8080") // 返回 TCPPort(8080)
|
||||
// ParsePort2("tcp:8080-8090") // 返回 TCPRangePort([2]int{8080, 8090})
|
||||
// ParsePort2("udp:5000") // 返回 UDPPort(5000)
|
||||
// ParsePort2("udp:5000-5010") // 返回 UDPRangePort([2]int{5000, 5010})
|
||||
func ParsePort2(conf string) (ret any, err error) {
|
||||
var port Port
|
||||
port, err = ParsePort(conf)
|
||||
@@ -58,10 +102,84 @@ func ParsePort2(conf string) (ret any, err error) {
|
||||
return UDPPort(port.Ports[0]), nil
|
||||
}
|
||||
|
||||
// ParsePort 解析端口配置字符串为 Port 结构体
|
||||
// 支持协议前缀、端口号/端口范围以及端口映射的解析
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// conf - 端口配置字符串,格式:
|
||||
// - "protocol:port" 单端口,如 "tcp:8080"
|
||||
// - "protocol:port1-port2" 端口范围,如 "tcp:8080-8090"
|
||||
// - "protocol:port:mapPort" 单端口映射,如 "tcp:8080:9090"
|
||||
// - "protocol:port:mapPort1-mapPort2" 单端口映射到端口范围,如 "tcp:8080:9000-9010"
|
||||
// - "protocol:port1-port2:mapPort1-mapPort2" 端口范围映射,如 "tcp:8080-8090:9000-9010"
|
||||
//
|
||||
// 返回值:
|
||||
//
|
||||
// ret - Port 结构体,包含协议、端口和映射端口信息
|
||||
// err - 解析错误
|
||||
//
|
||||
// 注意:
|
||||
// - 如果端口范围中 min > max,会自动交换顺序
|
||||
// - 单端口时,Ports[0] 和 Ports[1] 值相同
|
||||
// - 端口映射时,Map[0] 和 Map[1] 存储映射的目标端口范围
|
||||
// - 单个映射端口时,Map[0] 和 Map[1] 值相同
|
||||
//
|
||||
// 示例:
|
||||
//
|
||||
// ParsePort("tcp:8080") // Port{Protocol:"tcp", Ports:[2]int{8080, 8080}, Map:[2]int{0, 0}}
|
||||
// ParsePort("tcp:8080-8090") // Port{Protocol:"tcp", Ports:[2]int{8080, 8090}, Map:[2]int{0, 0}}
|
||||
// ParsePort("tcp:8080:9090") // Port{Protocol:"tcp", Ports:[2]int{8080, 8080}, Map:[2]int{9090, 9090}}
|
||||
// ParsePort("tcp:8080:9000-9010") // Port{Protocol:"tcp", Ports:[2]int{8080, 8080}, Map:[2]int{9000, 9010}}
|
||||
// ParsePort("tcp:8080-8090:9000-9010") // Port{Protocol:"tcp", Ports:[2]int{8080, 8090}, Map:[2]int{9000, 9010}}
|
||||
// ParsePort("udp:5000") // Port{Protocol:"udp", Ports:[2]int{5000, 5000}, Map:[2]int{0, 0}}
|
||||
// ParsePort("udp:5010-5000") // Port{Protocol:"udp", Ports:[2]int{5000, 5010}, Map:[2]int{0, 0}}
|
||||
func ParsePort(conf string) (ret Port, err error) {
|
||||
var port string
|
||||
var port, mapPort string
|
||||
var min, max int
|
||||
ret.Protocol, port, _ = strings.Cut(conf, ":")
|
||||
|
||||
// 按冒号分割,支持端口映射
|
||||
parts := strings.Split(conf, ":")
|
||||
if len(parts) < 2 || len(parts) > 3 {
|
||||
err = strconv.ErrSyntax
|
||||
return
|
||||
}
|
||||
|
||||
ret.Protocol = parts[0]
|
||||
port = parts[1]
|
||||
|
||||
// 处理端口映射
|
||||
if len(parts) == 3 {
|
||||
mapPort = parts[2]
|
||||
// 解析映射端口,支持单端口和端口范围
|
||||
if mapRange := strings.Split(mapPort, "-"); len(mapRange) == 2 {
|
||||
// 映射端口范围
|
||||
var mapMin, mapMax int
|
||||
mapMin, err = strconv.Atoi(mapRange[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
mapMax, err = strconv.Atoi(mapRange[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if mapMin < mapMax {
|
||||
ret.Map[0], ret.Map[1] = mapMin, mapMax
|
||||
} else {
|
||||
ret.Map[0], ret.Map[1] = mapMax, mapMin
|
||||
}
|
||||
} else {
|
||||
// 单个映射端口
|
||||
var mapPortNum int
|
||||
mapPortNum, err = strconv.Atoi(mapPort)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ret.Map[0], ret.Map[1] = mapPortNum, mapPortNum
|
||||
}
|
||||
}
|
||||
|
||||
// 处理端口范围
|
||||
if r := strings.Split(port, "-"); len(r) == 2 {
|
||||
min, err = strconv.Atoi(r[0])
|
||||
if err != nil {
|
||||
@@ -76,7 +194,12 @@ func ParsePort(conf string) (ret Port, err error) {
|
||||
} else {
|
||||
ret.Ports[0], ret.Ports[1] = max, min
|
||||
}
|
||||
} else if p, err := strconv.Atoi(port); err == nil {
|
||||
} else {
|
||||
var p int
|
||||
p, err = strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ret.Ports[0], ret.Ports[1] = p, p
|
||||
}
|
||||
return
|
||||
|
370
pkg/port_test.go
Normal file
370
pkg/port_test.go
Normal file
@@ -0,0 +1,370 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParsePort(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected Port
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
name: "TCP单端口",
|
||||
input: "tcp:8080",
|
||||
expected: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8080},
|
||||
Map: [2]int{0, 0},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "TCP端口范围",
|
||||
input: "tcp:8080-8090",
|
||||
expected: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8090},
|
||||
Map: [2]int{0, 0},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "TCP端口范围(反序)",
|
||||
input: "tcp:8090-8080",
|
||||
expected: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8090},
|
||||
Map: [2]int{0, 0},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "TCP单端口映射到单端口",
|
||||
input: "tcp:8080:9090",
|
||||
expected: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8080},
|
||||
Map: [2]int{9090, 9090},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "TCP单端口映射到端口范围",
|
||||
input: "tcp:8080:9000-9010",
|
||||
expected: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8080},
|
||||
Map: [2]int{9000, 9010},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "TCP端口范围映射到端口范围",
|
||||
input: "tcp:8080-8090:9000-9010",
|
||||
expected: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8090},
|
||||
Map: [2]int{9000, 9010},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "UDP单端口",
|
||||
input: "udp:5000",
|
||||
expected: Port{
|
||||
Protocol: "udp",
|
||||
Ports: [2]int{5000, 5000},
|
||||
Map: [2]int{0, 0},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "UDP端口范围",
|
||||
input: "udp:5000-5010",
|
||||
expected: Port{
|
||||
Protocol: "udp",
|
||||
Ports: [2]int{5000, 5010},
|
||||
Map: [2]int{0, 0},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "UDP端口映射",
|
||||
input: "udp:5000:6000",
|
||||
expected: Port{
|
||||
Protocol: "udp",
|
||||
Ports: [2]int{5000, 5000},
|
||||
Map: [2]int{6000, 6000},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "UDP端口范围映射(映射范围反序)",
|
||||
input: "udp:5000-5010:6010-6000",
|
||||
expected: Port{
|
||||
Protocol: "udp",
|
||||
Ports: [2]int{5000, 5010},
|
||||
Map: [2]int{6000, 6010},
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
// 错误情况
|
||||
{
|
||||
name: "缺少协议",
|
||||
input: "8080",
|
||||
expected: Port{},
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "过多冒号",
|
||||
input: "tcp:8080:9090:extra",
|
||||
expected: Port{},
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "无效端口号",
|
||||
input: "tcp:abc",
|
||||
expected: Port{},
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "无效映射端口号",
|
||||
input: "tcp:8080:abc",
|
||||
expected: Port{},
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "无效端口范围",
|
||||
input: "tcp:8080-abc",
|
||||
expected: Port{},
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "无效映射端口范围",
|
||||
input: "tcp:8080:9000-abc",
|
||||
expected: Port{},
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := ParsePort(tt.input)
|
||||
|
||||
if tt.hasError {
|
||||
if err == nil {
|
||||
t.Errorf("期望有错误,但没有错误")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("意外的错误: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if result.Protocol != tt.expected.Protocol {
|
||||
t.Errorf("协议不匹配: 期望 %s, 得到 %s", tt.expected.Protocol, result.Protocol)
|
||||
}
|
||||
|
||||
if result.Ports != tt.expected.Ports {
|
||||
t.Errorf("端口不匹配: 期望 %v, 得到 %v", tt.expected.Ports, result.Ports)
|
||||
}
|
||||
|
||||
if result.Map != tt.expected.Map {
|
||||
t.Errorf("映射端口不匹配: 期望 %v, 得到 %v", tt.expected.Map, result.Map)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPortMethods(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
port Port
|
||||
expectTCP bool
|
||||
expectUDP bool
|
||||
expectRange bool
|
||||
expectMapping bool
|
||||
expectRangeMap bool
|
||||
expectString string
|
||||
}{
|
||||
{
|
||||
name: "TCP单端口",
|
||||
port: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8080},
|
||||
Map: [2]int{0, 0},
|
||||
},
|
||||
expectTCP: true,
|
||||
expectUDP: false,
|
||||
expectRange: false,
|
||||
expectMapping: false,
|
||||
expectRangeMap: false,
|
||||
expectString: "tcp:8080",
|
||||
},
|
||||
{
|
||||
name: "TCP端口范围",
|
||||
port: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8090},
|
||||
Map: [2]int{0, 0},
|
||||
},
|
||||
expectTCP: true,
|
||||
expectUDP: false,
|
||||
expectRange: true,
|
||||
expectMapping: false,
|
||||
expectRangeMap: false,
|
||||
expectString: "tcp:8080-8090",
|
||||
},
|
||||
{
|
||||
name: "TCP单端口映射",
|
||||
port: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8080},
|
||||
Map: [2]int{9090, 9090},
|
||||
},
|
||||
expectTCP: true,
|
||||
expectUDP: false,
|
||||
expectRange: false,
|
||||
expectMapping: true,
|
||||
expectRangeMap: false,
|
||||
expectString: "tcp:8080:9090",
|
||||
},
|
||||
{
|
||||
name: "TCP端口范围映射",
|
||||
port: Port{
|
||||
Protocol: "tcp",
|
||||
Ports: [2]int{8080, 8090},
|
||||
Map: [2]int{9000, 9010},
|
||||
},
|
||||
expectTCP: true,
|
||||
expectUDP: false,
|
||||
expectRange: true,
|
||||
expectMapping: true,
|
||||
expectRangeMap: true,
|
||||
expectString: "tcp:8080-8090:9000-9010",
|
||||
},
|
||||
{
|
||||
name: "UDP单端口映射到端口范围",
|
||||
port: Port{
|
||||
Protocol: "udp",
|
||||
Ports: [2]int{5000, 5000},
|
||||
Map: [2]int{6000, 6010},
|
||||
},
|
||||
expectTCP: false,
|
||||
expectUDP: true,
|
||||
expectRange: false,
|
||||
expectMapping: true,
|
||||
expectRangeMap: true,
|
||||
expectString: "udp:5000:6000-6010",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.port.IsTCP() != tt.expectTCP {
|
||||
t.Errorf("IsTCP(): 期望 %v, 得到 %v", tt.expectTCP, tt.port.IsTCP())
|
||||
}
|
||||
|
||||
if tt.port.IsUDP() != tt.expectUDP {
|
||||
t.Errorf("IsUDP(): 期望 %v, 得到 %v", tt.expectUDP, tt.port.IsUDP())
|
||||
}
|
||||
|
||||
if tt.port.IsRange() != tt.expectRange {
|
||||
t.Errorf("IsRange(): 期望 %v, 得到 %v", tt.expectRange, tt.port.IsRange())
|
||||
}
|
||||
|
||||
if tt.port.HasMapping() != tt.expectMapping {
|
||||
t.Errorf("HasMapping(): 期望 %v, 得到 %v", tt.expectMapping, tt.port.HasMapping())
|
||||
}
|
||||
|
||||
if tt.port.IsRangeMapping() != tt.expectRangeMap {
|
||||
t.Errorf("IsRangeMapping(): 期望 %v, 得到 %v", tt.expectRangeMap, tt.port.IsRangeMapping())
|
||||
}
|
||||
|
||||
if tt.port.String() != tt.expectString {
|
||||
t.Errorf("String(): 期望 %s, 得到 %s", tt.expectString, tt.port.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePort2(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expectedType string
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
name: "TCP单端口",
|
||||
input: "tcp:8080",
|
||||
expectedType: "TCPPort",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "TCP端口范围",
|
||||
input: "tcp:8080-8090",
|
||||
expectedType: "TCPRangePort",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "UDP单端口",
|
||||
input: "udp:5000",
|
||||
expectedType: "UDPPort",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "UDP端口范围",
|
||||
input: "udp:5000-5010",
|
||||
expectedType: "UDPRangePort",
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
name: "无效输入",
|
||||
input: "invalid",
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := ParsePort2(tt.input)
|
||||
|
||||
if tt.hasError {
|
||||
if err == nil {
|
||||
t.Errorf("期望有错误,但没有错误")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("意外的错误: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch tt.expectedType {
|
||||
case "TCPPort":
|
||||
if _, ok := result.(TCPPort); !ok {
|
||||
t.Errorf("期望类型 TCPPort, 得到 %T", result)
|
||||
}
|
||||
case "TCPRangePort":
|
||||
if _, ok := result.(TCPRangePort); !ok {
|
||||
t.Errorf("期望类型 TCPRangePort, 得到 %T", result)
|
||||
}
|
||||
case "UDPPort":
|
||||
if _, ok := result.(UDPPort); !ok {
|
||||
t.Errorf("期望类型 UDPPort, 得到 %T", result)
|
||||
}
|
||||
case "UDPRangePort":
|
||||
if _, ok := result.(UDPRangePort); !ok {
|
||||
t.Errorf("期望类型 UDPRangePort, 得到 %T", result)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -37,12 +37,13 @@ var (
|
||||
|
||||
type WebRTCPlugin struct {
|
||||
m7s.Plugin
|
||||
ICEServers []ICEServer `desc:"ice服务器配置"`
|
||||
Port string `default:"tcp:9000" desc:"监听端口"`
|
||||
PLI time.Duration `default:"2s" desc:"发送PLI请求间隔"` // 视频流丢包后,发送PLI请求
|
||||
EnableDC bool `default:"true" desc:"是否启用DataChannel"` // 在不支持编码格式的情况下是否启用DataChannel传输
|
||||
MimeType []string `desc:"MimeType过滤列表,为空则不过滤"` // MimeType过滤列表,支持的格式如:video/H264, audio/opus
|
||||
s SettingEngine
|
||||
ICEServers []ICEServer `desc:"ice服务器配置"`
|
||||
Port string `default:"tcp:9000" desc:"监听端口"`
|
||||
PLI time.Duration `default:"2s" desc:"发送PLI请求间隔"` // 视频流丢包后,发送PLI请求
|
||||
EnableDC bool `default:"true" desc:"是否启用DataChannel"` // 在不支持编码格式的情况下是否启用DataChannel传输
|
||||
MimeType []string `desc:"MimeType过滤列表,为空则不过滤"` // MimeType过滤列表,支持的格式如:video/H264, audio/opus
|
||||
s SettingEngine
|
||||
portMapping map[int]int // 内部端口到外部端口的映射
|
||||
}
|
||||
|
||||
func (p *WebRTCPlugin) RegisterHandler() map[string]http.HandlerFunc {
|
||||
@@ -306,50 +307,90 @@ func (p *WebRTCPlugin) initSettingEngine() error {
|
||||
|
||||
// configurePort 配置端口设置
|
||||
func (p *WebRTCPlugin) configurePort() error {
|
||||
ports, err := ParsePort2(p.Port)
|
||||
// 使用 ParsePort 而不是 ParsePort2 来获取端口映射信息
|
||||
portInfo, err := ParsePort(p.Port)
|
||||
if err != nil {
|
||||
p.Error("webrtc port config error", "error", err, "port", p.Port)
|
||||
return err
|
||||
}
|
||||
|
||||
switch v := ports.(type) {
|
||||
case TCPPort:
|
||||
tcpport := int(v)
|
||||
tcpl, err := net.ListenTCP("tcp", &net.TCPAddr{
|
||||
IP: net.IP{0, 0, 0, 0},
|
||||
Port: tcpport,
|
||||
})
|
||||
p.OnDispose(func() {
|
||||
_ = tcpl.Close()
|
||||
})
|
||||
if err != nil {
|
||||
p.Error("webrtc listener tcp", "error", err)
|
||||
// 初始化端口映射
|
||||
p.portMapping = make(map[int]int)
|
||||
|
||||
// 如果有端口映射,存储映射关系
|
||||
if portInfo.HasMapping() {
|
||||
if portInfo.IsRange() {
|
||||
// 端口范围映射
|
||||
for i := 0; i <= portInfo.Ports[1]-portInfo.Ports[0]; i++ {
|
||||
internalPort := portInfo.Ports[0] + i
|
||||
var externalPort int
|
||||
if portInfo.IsRangeMapping() {
|
||||
// 映射端口也是范围
|
||||
externalPort = portInfo.Map[0] + i
|
||||
} else {
|
||||
// 映射端口是单个端口
|
||||
externalPort = portInfo.Map[0]
|
||||
}
|
||||
p.portMapping[internalPort] = externalPort
|
||||
}
|
||||
} else {
|
||||
// 单端口映射
|
||||
p.portMapping[portInfo.Ports[0]] = portInfo.Map[0]
|
||||
}
|
||||
p.SetDescription("tcp", fmt.Sprintf("%d", tcpport))
|
||||
p.Info("webrtc start listen", "port", tcpport)
|
||||
p.s.SetICETCPMux(NewICETCPMux(nil, tcpl, 4096))
|
||||
p.s.SetNetworkTypes([]NetworkType{NetworkTypeTCP4, NetworkTypeTCP6})
|
||||
p.s.DisableSRTPReplayProtection(true)
|
||||
case UDPRangePort:
|
||||
p.s.SetEphemeralUDPPortRange(uint16(v[0]), uint16(v[1]))
|
||||
p.SetDescription("udp", fmt.Sprintf("%d-%d", v[0], v[1]))
|
||||
case UDPPort:
|
||||
// 创建共享WEBRTC端口 默认9000
|
||||
udpListener, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||
IP: net.IP{0, 0, 0, 0},
|
||||
Port: int(v),
|
||||
})
|
||||
p.OnDispose(func() {
|
||||
_ = udpListener.Close()
|
||||
})
|
||||
if err != nil {
|
||||
p.Error("webrtc listener udp", "error", err)
|
||||
return err
|
||||
p.Info("Port mapping configured", "mapping", p.portMapping)
|
||||
}
|
||||
|
||||
// 根据协议类型进行配置
|
||||
if portInfo.IsTCP() {
|
||||
if portInfo.IsRange() {
|
||||
// TCP端口范围,这里可能需要特殊处理
|
||||
p.Error("TCP port range not supported in current implementation")
|
||||
return fmt.Errorf("TCP port range not supported")
|
||||
} else {
|
||||
// TCP单端口
|
||||
tcpport := portInfo.Ports[0]
|
||||
tcpl, err := net.ListenTCP("tcp", &net.TCPAddr{
|
||||
IP: net.IP{0, 0, 0, 0},
|
||||
Port: tcpport,
|
||||
})
|
||||
p.OnDispose(func() {
|
||||
_ = tcpl.Close()
|
||||
})
|
||||
if err != nil {
|
||||
p.Error("webrtc listener tcp", "error", err)
|
||||
return err
|
||||
}
|
||||
p.SetDescription("tcp", fmt.Sprintf("%d", tcpport))
|
||||
p.Info("webrtc start listen", "port", tcpport)
|
||||
p.s.SetICETCPMux(NewICETCPMux(nil, tcpl, 4096))
|
||||
p.s.SetNetworkTypes([]NetworkType{NetworkTypeTCP4, NetworkTypeTCP6})
|
||||
p.s.DisableSRTPReplayProtection(true)
|
||||
}
|
||||
} else {
|
||||
// UDP配置
|
||||
if portInfo.IsRange() {
|
||||
// UDP端口范围
|
||||
p.s.SetEphemeralUDPPortRange(uint16(portInfo.Ports[0]), uint16(portInfo.Ports[1]))
|
||||
p.SetDescription("udp", fmt.Sprintf("%d-%d", portInfo.Ports[0], portInfo.Ports[1]))
|
||||
} else {
|
||||
// UDP单端口
|
||||
udpport := portInfo.Ports[0]
|
||||
udpListener, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||
IP: net.IP{0, 0, 0, 0},
|
||||
Port: udpport,
|
||||
})
|
||||
p.OnDispose(func() {
|
||||
_ = udpListener.Close()
|
||||
})
|
||||
if err != nil {
|
||||
p.Error("webrtc listener udp", "error", err)
|
||||
return err
|
||||
}
|
||||
p.SetDescription("udp", fmt.Sprintf("%d", udpport))
|
||||
p.Info("webrtc start listen", "port", udpport)
|
||||
p.s.SetICEUDPMux(NewICEUDPMux(nil, udpListener))
|
||||
p.s.SetNetworkTypes([]NetworkType{NetworkTypeUDP4, NetworkTypeUDP6})
|
||||
}
|
||||
p.SetDescription("udp", fmt.Sprintf("%d", v))
|
||||
p.Info("webrtc start listen", "port", v)
|
||||
p.s.SetICEUDPMux(NewICEUDPMux(nil, udpListener))
|
||||
p.s.SetNetworkTypes([]NetworkType{NetworkTypeUDP4, NetworkTypeUDP6})
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -368,9 +409,33 @@ func (p *WebRTCPlugin) CreatePC(sd SessionDescription, conf Configuration) (pc *
|
||||
return
|
||||
}
|
||||
pc, err = api.NewPeerConnection(conf)
|
||||
if err == nil {
|
||||
err = pc.SetRemoteDescription(sd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果有端口映射配置,记录 ICE 候选者信息以供调试
|
||||
if len(p.portMapping) > 0 {
|
||||
pc.OnICECandidate(func(candidate *ICECandidate) {
|
||||
if candidate != nil {
|
||||
// 记录端口映射信息(用于调试和监控)
|
||||
if mappedPort, exists := p.portMapping[int(candidate.Port)]; exists {
|
||||
p.Debug("ICE candidate with port mapping detected",
|
||||
"original_port", candidate.Port,
|
||||
"mapped_port", mappedPort,
|
||||
"candidate_address", candidate.Address,
|
||||
"candidate_type", candidate.Typ)
|
||||
candidate.Port = uint16(mappedPort) // 更新候选者端口为映射后的端口
|
||||
} else {
|
||||
p.Debug("ICE candidate generated",
|
||||
"port", candidate.Port,
|
||||
"address", candidate.Address,
|
||||
"type", candidate.Typ)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
err = pc.SetRemoteDescription(sd)
|
||||
return
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user