mirror of
https://github.com/impact-eintr/netstack.git
synced 2025-10-06 05:16:50 +08:00
138 lines
4.6 KiB
Go
138 lines
4.6 KiB
Go
package stack
|
||
|
||
import (
|
||
"netstack/tcpip"
|
||
"netstack/tcpip/buffer"
|
||
"sync"
|
||
)
|
||
|
||
// 网络层协议号和传输层协议号的组合 当作分流器的key值
|
||
type protocolIDs struct {
|
||
network tcpip.NetworkProtocolNumber
|
||
transport tcpip.TransportProtocolNumber
|
||
}
|
||
|
||
type transportEndpoints struct {
|
||
mu sync.RWMutex
|
||
endpoints map[TransportEndpointID]TransportEndpoint
|
||
}
|
||
|
||
// transportDemuxer 解复用战队传输端点的数据包
|
||
// 他执行两级解复用:首先基于网络层和传输协议 然后基于端点ID
|
||
type transportDemuxer struct {
|
||
protocol map[protocolIDs]*transportEndpoints
|
||
}
|
||
|
||
// 新建一个分流器
|
||
func newTransportDemuxer(stack *Stack) *transportDemuxer {
|
||
d := &transportDemuxer{protocol: make(map[protocolIDs]*transportEndpoints)}
|
||
|
||
for netProto := range stack.networkProtocols {
|
||
for tranProto := range stack.transportProtocols {
|
||
d.protocol[protocolIDs{network: netProto, transport: tranProto}] = &transportEndpoints{
|
||
endpoints: make(map[TransportEndpointID]TransportEndpoint),
|
||
}
|
||
}
|
||
}
|
||
return d
|
||
}
|
||
|
||
// registerEndpoint 向分发器注册给定端点,以便将与端点ID匹配的数据包传递给它
|
||
func (d *transportDemuxer) registerEndpoint(netProtos []tcpip.NetworkProtocolNumber,
|
||
protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint) *tcpip.Error {
|
||
for i, n := range netProtos {
|
||
if err := d.singleRegisterEndpoint(n, protocol, id, ep); err != nil {
|
||
d.unregisterEndpoint(netProtos[:i], protocol, id) // 把刚才注册的注销掉
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (d *transportDemuxer) singleRegisterEndpoint(netProto tcpip.NetworkProtocolNumber,
|
||
protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint) *tcpip.Error {
|
||
eps, ok := d.protocol[protocolIDs{netProto, protocol}] // IPv4:udp
|
||
if !ok { // 未曾注册过这个传输端集合
|
||
return nil
|
||
}
|
||
|
||
eps.mu.Lock()
|
||
defer eps.mu.Unlock()
|
||
|
||
if _, ok := eps.endpoints[id]; ok { // 遍历传输端集合
|
||
return tcpip.ErrPortInUse
|
||
}
|
||
eps.endpoints[id] = ep
|
||
return nil
|
||
}
|
||
|
||
// unregisterEndpoint 使用给定的id注销端点,使其不再接收任何数据包
|
||
func (d *transportDemuxer) unregisterEndpoint(netProtos []tcpip.NetworkProtocolNumber,
|
||
protocol tcpip.TransportProtocolNumber, id TransportEndpointID) {
|
||
for _, n := range netProtos {
|
||
if eps, ok := d.protocol[protocolIDs{n, protocol}]; ok {
|
||
eps.mu.Lock()
|
||
delete(eps.endpoints, id)
|
||
eps.mu.Unlock()
|
||
}
|
||
}
|
||
}
|
||
|
||
// 根据传输层的id来找到对应的传输端,再将数据包交给这个传输端处理
|
||
func (d *transportDemuxer) deliverPacket(r *Route, protocol tcpip.TransportProtocolNumber, vv buffer.VectorisedView, id TransportEndpointID) bool {
|
||
// 先看看分流器里有没有注册相关协议端,如果没有则返回false
|
||
eps, ok := d.protocol[protocolIDs{r.NetProto, protocol}]
|
||
if !ok {
|
||
return false
|
||
}
|
||
// 从 eps 中找符合 id 的传输端
|
||
eps.mu.RLock()
|
||
ep := d.findEndpointLocked(eps, vv, id)
|
||
eps.mu.RUnlock()
|
||
|
||
if ep == nil {
|
||
return false
|
||
}
|
||
|
||
// Deliver the packet
|
||
ep.HandlePacket(r, id, vv)
|
||
|
||
return true
|
||
}
|
||
|
||
func (d *transportDemuxer) deliverControlPacket(net tcpip.NetworkProtocolNumber,
|
||
trans tcpip.TransportProtocolNumber, typ ControlType, extra uint32, vv buffer.VectorisedView, id TransportEndpointID) bool {
|
||
return false
|
||
}
|
||
|
||
// 根据传输层id来找到相应的传输层端
|
||
// 当本地没有存在连接的时候 只有 LocalAddr:LocalPort 监听的传输端 也就是客户端来建立新连接
|
||
// 当本地存在连接的时候 就有可能找到 LAddr:LPort+RAddr:RPort 的传输端
|
||
func (d *transportDemuxer) findEndpointLocked(eps *transportEndpoints,
|
||
vv buffer.VectorisedView, id TransportEndpointID) TransportEndpoint {
|
||
if ep := eps.endpoints[id]; ep != nil { // IPv4:udp
|
||
return ep
|
||
}
|
||
// Try to find a match with the id minus the local address.
|
||
nid := id
|
||
// 如果上面的 endpoints 没有找到,那么去掉本地ip地址,看看有没有相应的传输层端
|
||
// 因为有时候传输层监听的时候没有绑定本地ip,也就是 any address,此时的 LocalAddress
|
||
// 为空。
|
||
nid.LocalAddress = ""
|
||
if ep := eps.endpoints[nid]; ep != nil {
|
||
return ep
|
||
}
|
||
|
||
// Try to find a match with the id minus the remote part.
|
||
nid.LocalAddress = id.LocalAddress
|
||
nid.RemoteAddress = ""
|
||
nid.RemotePort = 0
|
||
if ep := eps.endpoints[nid]; ep != nil {
|
||
return ep
|
||
}
|
||
|
||
// Try to find a match with only the local port.
|
||
nid.LocalAddress = ""
|
||
return eps.endpoints[nid]
|
||
}
|