Files
goodlink/netstack/endpoint_windows.go
2025-04-17 15:15:22 +08:00

198 lines
5.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//go:build windows
package netstack
import (
"context"
"errors"
"io"
"sync"
"gvisor.dev/gvisor/pkg/buffer"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
const (
// Queue length for outbound packet, arriving for read. Overflow
// causes packet drops.
defaultOutQueueLen = 1 << 10
)
// Endpoint implements the interface of stack.LinkEndpoint from io.ReadWriter.
type Endpoint struct {
*channel.Endpoint
// rw is the io.ReadWriter for reading and writing packets.
rw io.ReadWriter
// mtu (maximum transmission unit) is the maximum size of a packet.
mtu uint32
// offset can be useful when perform TUN device I/O with TUN_PI enabled.
offset int
// once is used to perform the init action once when attaching.
once sync.Once
// wg keeps track of running goroutines.
wg sync.WaitGroup
}
// New returns stack.LinkEndpoint(.*Endpoint) and error.
func NewEndpoint(rw io.ReadWriter, mtu uint32, offset int) (*Endpoint, error) {
// 校验MTU最大传输单元有效性
if mtu == 0 {
return nil, errors.New("MTU size is zero")
}
// 确保IO接口有效
if rw == nil {
return nil, errors.New("RW interface is nil")
}
// 校验偏移量合法性用于TUN设备头
if offset < 0 {
return nil, errors.New("offset must be non-negative")
}
// 创建并初始化端点实例
return &Endpoint{
Endpoint: channel.New(
defaultOutQueueLen, // 发包队列长度1024
mtu, // 最大传输单元
"", // 链路层名称(保留空)
),
rw: rw, // 底层IO读写接口
mtu: mtu, // 保存MTU配置
offset: offset, // TUN设备头偏移量
}, nil
}
// Attach启动从io读取数据包的例程。读者和 //通过提供的分派器分派它们。
// 调用Attach后Endpoint将开始从底层IO接口读取数据包并
func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) {
// 调用基类方法附加网络调度器
e.Endpoint.Attach(dispatcher)
// 使用sync.Once确保初始化逻辑只执行一次
e.once.Do(func() {
// 创建带取消功能的上下文用于goroutine退出控制
ctx, cancel := context.WithCancel(context.Background())
// 设置等待组计数器两个后台goroutine
e.wg.Add(2)
// 启动发包处理协程
go func() {
e.outboundLoop(ctx) // 处理出站数据包
e.wg.Done() // 协程结束计数器减1
}()
// 启动收包处理协程
go func() {
e.dispatchLoop(cancel) // 处理入站数据包传递cancel函数
e.wg.Done() // 协程结束计数器减1
}()
})
}
func (e *Endpoint) Wait() {
e.wg.Wait()
}
// dispatchLoop dispatches packets to upper layer.
func (e *Endpoint) dispatchLoop(cancel context.CancelFunc) {
// 确保退出时取消上下文通知outboundLoop终止
defer cancel()
// 获取配置参数数据偏移量和MTU值
offset, mtu := e.offset, int(e.mtu)
// 创建带偏移量的接收缓冲区用于TUN设备头
data := make([]byte, offset+mtu)
// 数据包接收主循环
for {
// 创建带偏移量的接收缓冲区用于TUN设备头
// data := make([]byte, offset+mtu)
// 从IO接口读取原始数据
n, err := e.rw.Read(data)
if err != nil {
break // 发生致命错误时退出循环
}
// 过滤无效数据包空包或超过MTU大小的包
if n == 0 || n > mtu {
continue
}
// 检查端点是否已附加到协议栈
if !e.IsAttached() {
continue /* 未附加时丢弃数据包 */
}
// 创建协议栈数据包缓冲区
// 从偏移量开始截取有效载荷跳过TUN头
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Payload: buffer.MakeWithData(data[offset : offset+n]),
})
// 根据IP版本分发数据包
switch header.IPVersion(data[offset:]) {
case header.IPv4Version:
e.InjectInbound(header.IPv4ProtocolNumber, pkt) // 注入IPv4协议栈
case header.IPv6Version:
//e.InjectInbound(header.IPv6ProtocolNumber, pkt) // 注入IPv6协议栈
}
pkt.DecRef() // 释放数据包引用计数
}
}
// outboundLoop reads outbound packets from channel, and then it calls
// writePacket to send those packets back to lower layer.
func (e *Endpoint) outboundLoop(ctx context.Context) {
// 出站数据包处理主循环
for {
// 从通道读取待发送数据包(支持上下文取消)
pkt := e.ReadContext(ctx)
// 读取到nil表示通道已关闭或上下文取消
if pkt == nil {
break
}
// 将数据包写入底层IO接口
e.writePacket(pkt)
}
}
// writePacket writes outbound packets to the io.Writer.
func (e *Endpoint) writePacket(pkt *stack.PacketBuffer) tcpip.Error {
// 确保数据包引用计数最终释放
defer pkt.DecRef()
// 转换数据包为可写缓冲区
buf := pkt.ToBuffer()
// 确保缓冲区资源最终释放
defer buf.Release()
// 添加TUN设备头偏移当offset非0时
if e.offset != 0 {
// 创建空白头部缓冲区长度等于offset
v := buffer.NewViewWithData(make([]byte, e.offset))
// 将头部预置到数据缓冲区前
_ = buf.Prepend(v)
}
// 将数据写入底层设备如TUN接口
if _, err := e.rw.Write(buf.Flatten()); err != nil {
// 返回端点状态错误(写入失败时)
return &tcpip.ErrInvalidEndpointState{}
}
return nil
}