mirror of
https://github.com/impact-eintr/netstack.git
synced 2025-10-24 21:20:20 +08:00
17
.vscode/c_cpp_properties.json
vendored
Normal file
17
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Win32",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"_DEBUG",
|
||||||
|
"UNICODE",
|
||||||
|
"_UNICODE"
|
||||||
|
],
|
||||||
|
"intelliSenseMode": "windows-msvc-x64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
@@ -3,12 +3,22 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
go func() {
|
||||||
_, err := net.Dial("tcp", "192.168.1.1:9999")
|
_, err := net.Dial("tcp", "192.168.1.1:9999")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("err : ", err)
|
fmt.Println("err : ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
t := time.NewTimer(500 * time.Millisecond)
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,10 +149,14 @@ func (s *Sleeper) AddWaker(w *Waker, id int) {
|
|||||||
|
|
||||||
// nextWaker returns the next waker in the notification list, blocking if
|
// nextWaker returns the next waker in the notification list, blocking if
|
||||||
// needed.
|
// needed.
|
||||||
|
// listenLoop的Sleeper尝试改变自己的调度 如果没有人等着催 就睡
|
||||||
|
// 设置了block的话 尝试去获取本地列表中的唤醒者 并取出最前面的唤醒者
|
||||||
|
// 要是本地列表为空 就去遍历共享列表
|
||||||
func (s *Sleeper) nextWaker(block bool) *Waker {
|
func (s *Sleeper) nextWaker(block bool) *Waker {
|
||||||
// Attempt to replenish the local list if it's currently empty.
|
// Attempt to replenish the local list if it's currently empty.
|
||||||
if s.localList == nil {
|
if s.localList == nil {
|
||||||
for atomic.LoadPointer(&s.sharedList) == nil {
|
// 首次进入循环 检查共享链表为空 可能需要睡
|
||||||
|
for atomic.LoadPointer(&s.sharedList) == nil { // 被唤醒 再次检查共享链表情况 很有可能有人催了
|
||||||
// Fail request if caller requested that we
|
// Fail request if caller requested that we
|
||||||
// don't block.
|
// don't block.
|
||||||
if !block {
|
if !block {
|
||||||
@@ -163,13 +167,13 @@ func (s *Sleeper) nextWaker(block bool) *Waker {
|
|||||||
// this allows them to abort the wait by setting
|
// this allows them to abort the wait by setting
|
||||||
// waitingG back to zero (which we'll notice
|
// waitingG back to zero (which we'll notice
|
||||||
// before committing the sleep).
|
// before committing the sleep).
|
||||||
atomic.StoreUintptr(&s.waitingG, preparingG)
|
atomic.StoreUintptr(&s.waitingG, preparingG) // 准备睡
|
||||||
|
|
||||||
// Check if something was queued while we were
|
// Check if something was queued while we were
|
||||||
// preparing to sleep. We need this interleaving
|
// preparing to sleep. We need this interleaving
|
||||||
// to avoid missing wake ups.
|
// to avoid missing wake ups.
|
||||||
if atomic.LoadPointer(&s.sharedList) != nil {
|
if atomic.LoadPointer(&s.sharedList) != nil { // 有人催了 不睡了
|
||||||
atomic.StoreUintptr(&s.waitingG, 0)
|
atomic.StoreUintptr(&s.waitingG, 0) // 放弃睡眠
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,16 +184,20 @@ func (s *Sleeper) nextWaker(block bool) *Waker {
|
|||||||
// commitSleep to decide whether to immediately
|
// commitSleep to decide whether to immediately
|
||||||
// wake the caller up or to leave it sleeping.
|
// wake the caller up or to leave it sleeping.
|
||||||
const traceEvGoBlockSelect = 24
|
const traceEvGoBlockSelect = 24
|
||||||
|
log.Println(atomic.LoadUintptr(&s.waitingG), "进入睡眠")
|
||||||
|
// 没人催 进入睡眠
|
||||||
gopark(commitSleep, &s.waitingG, "sleeper", traceEvGoBlockSelect, 0)
|
gopark(commitSleep, &s.waitingG, "sleeper", traceEvGoBlockSelect, 0)
|
||||||
}
|
}
|
||||||
|
log.Println(atomic.LoadPointer(&s.sharedList), "唤醒了", atomic.LoadUintptr(&s.waitingG))
|
||||||
|
|
||||||
// Pull the shared list out and reverse it in the local
|
// Pull the shared list out and reverse it in the local
|
||||||
// list. Given that wakers push themselves in reverse
|
// list. Given that wakers push themselves in reverse
|
||||||
// order, we fix things here.
|
// order, we fix things here.
|
||||||
v := (*Waker)(atomic.SwapPointer(&s.sharedList, nil))
|
// 将共享列表拉出来,在本地列表中反转。鉴于唤醒者以相反的顺序推动自己,我们在这里解决问题
|
||||||
for v != nil {
|
v := (*Waker)(atomic.SwapPointer(&s.sharedList, nil)) // 这里将唤醒者置空
|
||||||
|
for v != nil { // 共享链表有东西 找到最后一位
|
||||||
cur := v
|
cur := v
|
||||||
v = v.next
|
v = v.next // 向后遍历共享链表
|
||||||
|
|
||||||
cur.next = s.localList
|
cur.next = s.localList
|
||||||
s.localList = cur
|
s.localList = cur
|
||||||
@@ -216,6 +224,7 @@ func (s *Sleeper) nextWaker(block bool) *Waker {
|
|||||||
// allowed to call this method.
|
// allowed to call this method.
|
||||||
func (s *Sleeper) Fetch(block bool) (id int, ok bool) {
|
func (s *Sleeper) Fetch(block bool) (id int, ok bool) {
|
||||||
for {
|
for {
|
||||||
|
// 这个s是ListenLoop的Sleeper
|
||||||
w := s.nextWaker(block) // 如果没有 将暂停调度 call gopark
|
w := s.nextWaker(block) // 如果没有 将暂停调度 call gopark
|
||||||
if w == nil {
|
if w == nil {
|
||||||
return -1, false
|
return -1, false
|
||||||
@@ -283,11 +292,12 @@ func (s *Sleeper) Done() {
|
|||||||
|
|
||||||
// enqueueAssertedWaker enqueues an asserted waker to the "ready" circular list
|
// enqueueAssertedWaker enqueues an asserted waker to the "ready" circular list
|
||||||
// of wakers that want to notify the sleeper.
|
// of wakers that want to notify the sleeper.
|
||||||
func (s *Sleeper) enqueueAssertedWaker(w *Waker) {
|
func (s *Sleeper) enqueueAssertedWaker(w *Waker) { // w.s 是 assertSleeper
|
||||||
// Add the new waker to the front of the list.
|
// Add the new waker to the front of the list.
|
||||||
for {
|
for {
|
||||||
v := (*Waker)(atomic.LoadPointer(&s.sharedList))
|
v := (*Waker)(atomic.LoadPointer(&s.sharedList))
|
||||||
w.next = v
|
w.next = v
|
||||||
|
// 每个新连接的 newSegmentWaker.s.sharedList 初始化为 正在睡眠的 listenLoop 的waker
|
||||||
if atomic.CompareAndSwapPointer(&s.sharedList, uwaker(v), uwaker(w)) {
|
if atomic.CompareAndSwapPointer(&s.sharedList, uwaker(v), uwaker(w)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -296,7 +306,8 @@ func (s *Sleeper) enqueueAssertedWaker(w *Waker) {
|
|||||||
for {
|
for {
|
||||||
// Nothing to do if there isn't a G waiting.
|
// Nothing to do if there isn't a G waiting.
|
||||||
g := atomic.LoadUintptr(&s.waitingG)
|
g := atomic.LoadUintptr(&s.waitingG)
|
||||||
if g == 0 {
|
log.Println("tcp端 所在的G: ", g)
|
||||||
|
if g == 0 { // 0 表示 醒着
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,6 +315,7 @@ func (s *Sleeper) enqueueAssertedWaker(w *Waker) {
|
|||||||
if atomic.CompareAndSwapUintptr(&s.waitingG, g, 0) {
|
if atomic.CompareAndSwapUintptr(&s.waitingG, g, 0) {
|
||||||
if g != preparingG {
|
if g != preparingG {
|
||||||
// We managed to get a G. Wake it up.
|
// We managed to get a G. Wake it up.
|
||||||
|
log.Println(g, "去唤醒 0")
|
||||||
goready(g, 0)
|
goready(g, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,21 +359,23 @@ type Waker struct {
|
|||||||
// Assert moves the waker to an asserted state, if it isn't asserted yet. When
|
// Assert moves the waker to an asserted state, if it isn't asserted yet. When
|
||||||
// asserted, the waker will cause its matching sleeper to wake up.
|
// asserted, the waker will cause its matching sleeper to wake up.
|
||||||
func (w *Waker) Assert() {
|
func (w *Waker) Assert() {
|
||||||
log.Println("Assert...")
|
log.Println(unsafe.Pointer(w), "Assert", &assertedSleeper)
|
||||||
// Nothing to do if the waker is already asserted. This check allows us
|
// Nothing to do if the waker is already asserted. This check allows us
|
||||||
// to complete this case (already asserted) without any interlocked
|
// to complete this case (already asserted) without any interlocked
|
||||||
// operations on x86.
|
// operations on x86.
|
||||||
if atomic.LoadPointer(&w.s) == usleeper(&assertedSleeper) {
|
if atomic.LoadPointer(&w.s) == usleeper(&assertedSleeper) {
|
||||||
|
log.Println("已经叫过了")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("Asserting ...")
|
||||||
// Mark the waker as asserted, and wake up a sleeper if there is one.
|
// Mark the waker as asserted, and wake up a sleeper if there is one.
|
||||||
switch s := (*Sleeper)(atomic.SwapPointer(&w.s, usleeper(&assertedSleeper))); s {
|
switch s := (*Sleeper)(atomic.SwapPointer(&w.s, usleeper(&assertedSleeper))); s {
|
||||||
case nil:
|
case nil:
|
||||||
case &assertedSleeper:
|
case &assertedSleeper:
|
||||||
default:
|
default: // 初始态
|
||||||
log.Println("唤醒", s)
|
log.Println("唤醒", s.waitingG)
|
||||||
s.enqueueAssertedWaker(w) // call goready
|
s.enqueueAssertedWaker(w) // s 是tcp端的newSegmentWaker call goready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -261,11 +261,43 @@ func (b TCP) SetChecksum(checksum uint16) {
|
|||||||
binary.BigEndian.PutUint16(b[tcpChecksum:], checksum)
|
binary.BigEndian.PutUint16(b[tcpChecksum:], checksum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalculateChecksum calculates the checksum of the tcp segment given
|
||||||
|
// the totalLen and partialChecksum(descriptions below)
|
||||||
|
// totalLen is the total length of the segment
|
||||||
|
// partialChecksum is the checksum of the network-layer pseudo-header
|
||||||
|
// (excluding the total length) and the checksum of the segment data.
|
||||||
|
func (b TCP) CalculateChecksum(partialChecksum uint16, totalLen uint16) uint16 {
|
||||||
|
// Add the length portion of the checksum to the pseudo-checksum.
|
||||||
|
tmp := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(tmp, totalLen)
|
||||||
|
checksum := Checksum(tmp, partialChecksum)
|
||||||
|
|
||||||
|
// Calculate the rest of the checksum.
|
||||||
|
return Checksum(b[:b.DataOffset()], checksum)
|
||||||
|
}
|
||||||
|
|
||||||
// Options returns a slice that holds the unparsed TCP options in the segment.
|
// Options returns a slice that holds the unparsed TCP options in the segment.
|
||||||
func (b TCP) Options() []byte {
|
func (b TCP) Options() []byte {
|
||||||
return b[TCPMinimumSize:b.DataOffset()]
|
return b[TCPMinimumSize:b.DataOffset()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b TCP) encodeSubset(seq, ack uint32, flags uint8, rcvwnd uint16) {
|
||||||
|
binary.BigEndian.PutUint32(b[seqNum:], seq)
|
||||||
|
binary.BigEndian.PutUint32(b[ackNum:], ack)
|
||||||
|
b[tcpFlags] = flags
|
||||||
|
binary.BigEndian.PutUint16(b[winSize:], rcvwnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode encodes all the fields of the tcp header.
|
||||||
|
func (b TCP) Encode(t *TCPFields) {
|
||||||
|
b.encodeSubset(t.SeqNum, t.AckNum, t.Flags, t.WindowSize)
|
||||||
|
binary.BigEndian.PutUint16(b[srcPort:], t.SrcPort)
|
||||||
|
binary.BigEndian.PutUint16(b[dstPort:], t.DstPort)
|
||||||
|
b[dataOffset] = (t.DataOffset / 4) << 4
|
||||||
|
binary.BigEndian.PutUint16(b[tcpChecksum:], t.Checksum)
|
||||||
|
binary.BigEndian.PutUint16(b[urgentPtr:], t.UrgentPointer)
|
||||||
|
}
|
||||||
|
|
||||||
// ParseTCPOptions extracts and stores all known options in the provided byte
|
// ParseTCPOptions extracts and stores all known options in the provided byte
|
||||||
// slice in a TCPOptions structure.
|
// slice in a TCPOptions structure.
|
||||||
func ParseTCPOptions(b []byte) TCPOptions {
|
func ParseTCPOptions(b []byte) TCPOptions {
|
||||||
@@ -432,6 +464,112 @@ func (opts TCPSynOptions) String() string {
|
|||||||
return fmt.Sprintf("|%d|%d|%v|%d|%d|%v|", opts.MSS, opts.WS, opts.TS, opts.TSVal, opts.TSEcr, opts.SACKPermitted)
|
return fmt.Sprintf("|%d|%d|%v|%d|%d|%v|", opts.MSS, opts.WS, opts.TS, opts.TSVal, opts.TSEcr, opts.SACKPermitted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeMSSOption encodes the MSS TCP option with the provided MSS values in
|
||||||
|
// the supplied buffer. If the provided buffer is not large enough then it just
|
||||||
|
// returns without encoding anything. It returns the number of bytes written to
|
||||||
|
// the provided buffer.
|
||||||
|
func EncodeMSSOption(mss uint32, b []byte) int {
|
||||||
|
// mssOptionSize is the number of bytes in a valid MSS option.
|
||||||
|
const mssOptionSize = 4
|
||||||
|
|
||||||
|
if len(b) < mssOptionSize {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
b[0], b[1], b[2], b[3] = TCPOptionMSS, mssOptionSize, byte(mss>>8), byte(mss)
|
||||||
|
return mssOptionSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeWSOption encodes the WS TCP option with the WS value in the
|
||||||
|
// provided buffer. If the provided buffer is not large enough then it just
|
||||||
|
// returns without encoding anything. It returns the number of bytes written to
|
||||||
|
// the provided buffer.
|
||||||
|
func EncodeWSOption(ws int, b []byte) int {
|
||||||
|
if len(b) < 3 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
b[0], b[1], b[2] = TCPOptionWS, 3, uint8(ws)
|
||||||
|
return int(b[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeTSOption encodes the provided tsVal and tsEcr values as a TCP timestamp
|
||||||
|
// option into the provided buffer. If the buffer is smaller than expected it
|
||||||
|
// just returns without encoding anything. It returns the number of bytes
|
||||||
|
// written to the provided buffer.
|
||||||
|
func EncodeTSOption(tsVal, tsEcr uint32, b []byte) int {
|
||||||
|
if len(b) < 10 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
b[0], b[1] = TCPOptionTS, 10
|
||||||
|
binary.BigEndian.PutUint32(b[2:], tsVal)
|
||||||
|
binary.BigEndian.PutUint32(b[6:], tsEcr)
|
||||||
|
return int(b[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeSACKPermittedOption encodes a SACKPermitted option into the provided
|
||||||
|
// buffer. If the buffer is smaller than required it just returns without
|
||||||
|
// encoding anything. It returns the number of bytes written to the provided
|
||||||
|
// buffer.
|
||||||
|
func EncodeSACKPermittedOption(b []byte) int {
|
||||||
|
if len(b) < 2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
b[0], b[1] = TCPOptionSACKPermitted, 2
|
||||||
|
return int(b[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeSACKBlocks encodes the provided SACK blocks as a TCP SACK option block
|
||||||
|
// in the provided slice. It tries to fit in as many blocks as possible based on
|
||||||
|
// number of bytes available in the provided buffer. It returns the number of
|
||||||
|
// bytes written to the provided buffer.
|
||||||
|
func EncodeSACKBlocks(sackBlocks []SACKBlock, b []byte) int {
|
||||||
|
if len(sackBlocks) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
l := len(sackBlocks)
|
||||||
|
if l > TCPMaxSACKBlocks {
|
||||||
|
l = TCPMaxSACKBlocks
|
||||||
|
}
|
||||||
|
if ll := (len(b) - 2) / 8; ll < l {
|
||||||
|
l = ll
|
||||||
|
}
|
||||||
|
if l == 0 {
|
||||||
|
// There is not enough space in the provided buffer to add
|
||||||
|
// any SACK blocks.
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
b[0] = TCPOptionSACK
|
||||||
|
b[1] = byte(l*8 + 2)
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
binary.BigEndian.PutUint32(b[i*8+2:], uint32(sackBlocks[i].Start))
|
||||||
|
binary.BigEndian.PutUint32(b[i*8+6:], uint32(sackBlocks[i].End))
|
||||||
|
}
|
||||||
|
return int(b[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeNOP adds an explicit NOP to the option list.
|
||||||
|
func EncodeNOP(b []byte) int {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
b[0] = TCPOptionNOP
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTCPOptionPadding adds the required number of TCPOptionNOP to quad align
|
||||||
|
// the option buffer. It adds padding bytes after the offset specified and
|
||||||
|
// returns the number of padding bytes added. The passed in options slice
|
||||||
|
// must have space for the padding bytes.
|
||||||
|
func AddTCPOptionPadding(options []byte, offset int) int {
|
||||||
|
paddingToAdd := -offset & 3
|
||||||
|
// Now add any padding bytes that might be required to quad align the
|
||||||
|
// options.
|
||||||
|
for i := offset; i < offset+paddingToAdd; i++ {
|
||||||
|
options[i] = TCPOptionNOP
|
||||||
|
}
|
||||||
|
return paddingToAdd
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
0 1 2 3
|
0 1 2 3
|
||||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
|||||||
@@ -306,7 +306,6 @@ func (e *endpoint) protocolListenLoop(rcvWnd seqnum.Size) *tcpip.Error {
|
|||||||
for {
|
for {
|
||||||
switch index, _ := s.Fetch(true); index { // Fetch(true) 阻塞获取
|
switch index, _ := s.Fetch(true); index { // Fetch(true) 阻塞获取
|
||||||
case wakerForNewSegment:
|
case wakerForNewSegment:
|
||||||
log.Println("处理处理")
|
|
||||||
mayRequeue := true
|
mayRequeue := true
|
||||||
// 接收和处理tcp报文
|
// 接收和处理tcp报文
|
||||||
for i := 0; i < maxSegmentsPerWake; i++ {
|
for i := 0; i < maxSegmentsPerWake; i++ {
|
||||||
@@ -325,6 +324,7 @@ func (e *endpoint) protocolListenLoop(rcvWnd seqnum.Size) *tcpip.Error {
|
|||||||
}
|
}
|
||||||
case wakerForNotification:
|
case wakerForNotification:
|
||||||
// TODO 触发其他事件
|
// TODO 触发其他事件
|
||||||
|
log.Println("其他事件?")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ package tcp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"netstack/sleep"
|
||||||
"netstack/tcpip"
|
"netstack/tcpip"
|
||||||
"netstack/tcpip/buffer"
|
"netstack/tcpip/buffer"
|
||||||
"netstack/tcpip/header"
|
"netstack/tcpip/header"
|
||||||
"netstack/tcpip/seqnum"
|
"netstack/tcpip/seqnum"
|
||||||
"netstack/tcpip/stack"
|
"netstack/tcpip/stack"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxSegmentsPerWake = 100
|
const maxSegmentsPerWake = 100
|
||||||
@@ -108,11 +112,50 @@ func (h *handshake) resetToSynRcvd(iss seqnum.Value, irs seqnum.Value, opts *hea
|
|||||||
log.Println("发送 syn|ack 确认报文 设置tcp状态为 [rcvd]")
|
log.Println("发送 syn|ack 确认报文 设置tcp状态为 [rcvd]")
|
||||||
h.flags = flagSyn | flagAck
|
h.flags = flagSyn | flagAck
|
||||||
h.iss = iss
|
h.iss = iss
|
||||||
h.ackNum = irs + 1
|
h.ackNum = irs + 1 // NOTE ACK = synNum + 1
|
||||||
h.mss = opts.MSS
|
h.mss = opts.MSS
|
||||||
h.sndWndScale = opts.WS
|
h.sndWndScale = opts.WS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *handshake) resolveRoute() *tcpip.Error {
|
||||||
|
log.Printf("tcp resolveRoute")
|
||||||
|
// Set up the wakers.
|
||||||
|
s := sleep.Sleeper{}
|
||||||
|
resolutionWaker := &sleep.Waker{}
|
||||||
|
s.AddWaker(resolutionWaker, wakerForResolution)
|
||||||
|
s.AddWaker(&h.ep.notificationWaker, wakerForNotification)
|
||||||
|
defer s.Done()
|
||||||
|
|
||||||
|
// Initial action is to resolve route.
|
||||||
|
index := wakerForResolution
|
||||||
|
for {
|
||||||
|
log.Println(index)
|
||||||
|
switch index {
|
||||||
|
case wakerForResolution:
|
||||||
|
if _, err := h.ep.route.Resolve(resolutionWaker); err != tcpip.ErrWouldBlock {
|
||||||
|
// Either success (err == nil) or failure.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Resolution not completed. Keep trying...
|
||||||
|
|
||||||
|
case wakerForNotification:
|
||||||
|
// TODO
|
||||||
|
//n := h.ep.fetchNotifications()
|
||||||
|
//if n¬ifyClose != 0 {
|
||||||
|
// h.ep.route.RemoveWaker(resolutionWaker)
|
||||||
|
// return tcpip.ErrAborted
|
||||||
|
//}
|
||||||
|
//if n¬ifyDrain != 0 {
|
||||||
|
// close(h.ep.drainDone)
|
||||||
|
// <-h.ep.undrain
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for notification.
|
||||||
|
index, _ = s.Fetch(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// execute executes the TCP 3-way handshake.
|
// execute executes the TCP 3-way handshake.
|
||||||
// 执行tcp 3次握手,客户端和服务端都是调用该函数来实现三次握手
|
// 执行tcp 3次握手,客户端和服务端都是调用该函数来实现三次握手
|
||||||
/*
|
/*
|
||||||
@@ -127,20 +170,136 @@ func (h *handshake) resetToSynRcvd(iss seqnum.Value, irs seqnum.Value, opts *hea
|
|||||||
|------ack----->|established
|
|------ack----->|established
|
||||||
*/
|
*/
|
||||||
func (h *handshake) execute() *tcpip.Error {
|
func (h *handshake) execute() *tcpip.Error {
|
||||||
|
// 是否需要拿到下一条地址
|
||||||
|
if h.ep.route.IsResolutionRequired() {
|
||||||
|
if err := h.resolveRoute(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Initialize the resend timer.
|
||||||
|
// 初始化重传定时器
|
||||||
|
resendWaker := sleep.Waker{}
|
||||||
|
// 设置1s超时
|
||||||
|
timeOut := time.Duration(time.Second)
|
||||||
|
rt := time.AfterFunc(timeOut, func() {
|
||||||
|
resendWaker.Assert()
|
||||||
|
})
|
||||||
|
defer rt.Stop()
|
||||||
|
|
||||||
|
// Set up the wakers.
|
||||||
|
s := sleep.Sleeper{}
|
||||||
|
s.AddWaker(&resendWaker, wakerForResend)
|
||||||
|
s.AddWaker(&h.ep.notificationWaker, wakerForNotification)
|
||||||
|
s.AddWaker(&h.ep.newSegmentWaker, wakerForNewSegment)
|
||||||
|
defer s.Done()
|
||||||
|
|
||||||
// sync报文的选项参数
|
// sync报文的选项参数
|
||||||
synOpts := header.TCPSynOptions{}
|
synOpts := header.TCPSynOptions{}
|
||||||
// 如果是客户端发送 syn 报文,如果是服务端发送 syn+ack 报文
|
// 如果是客户端发送 syn 报文,如果是服务端发送 syn+ack 报文
|
||||||
sendSynTCP(&h.ep.route, h.ep.id, h.flags, h.iss, h.ackNum, h.rcvWnd, synOpts)
|
sendSynTCP(&h.ep.route, h.ep.id, h.flags, h.iss, h.ackNum, h.rcvWnd, synOpts)
|
||||||
|
|
||||||
|
for h.state != handshakeCompleted {
|
||||||
|
// 获取事件id
|
||||||
|
switch index, _ := s.Fetch(true); index {
|
||||||
|
case wakerForResend: // NOTE tcp超时重传机制
|
||||||
|
// 如果是客户端当发送 syn 报文,超过一定的时间未收到回包,触发超时重传
|
||||||
|
// 如果是服务端当发送 syn+ack 报文,超过一定的时间未收到 ack 回包,触发超时重传
|
||||||
|
// 超时时间变为上次的2倍
|
||||||
|
timeOut *= 2
|
||||||
|
if timeOut > 60*time.Second {
|
||||||
|
return tcpip.ErrTimeout
|
||||||
|
}
|
||||||
|
rt.Reset(timeOut)
|
||||||
|
// 重新发送syn报文
|
||||||
|
sendSynTCP(&h.ep.route, h.ep.id, h.flags, h.iss, h.ackNum, h.rcvWnd, synOpts)
|
||||||
|
|
||||||
|
case wakerForNotification:
|
||||||
|
|
||||||
|
case wakerForNewSegment:
|
||||||
|
// 处理握手报文
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var optionPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, maxOptionSize)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 减少资源浪费
|
||||||
|
func getOptions() []byte {
|
||||||
|
return optionPool.Get().([]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putOptions(options []byte) {
|
||||||
|
// Reslice to full capacity.
|
||||||
|
optionPool.Put(options[0:cap(options)])
|
||||||
|
}
|
||||||
|
|
||||||
|
// tcp选项的编码 将一个TCPSyncOptions编码到 []byte 中
|
||||||
|
func makeSynOptions(opts header.TCPSynOptions) []byte {
|
||||||
|
// Emulate linux option order. This is as follows:
|
||||||
|
//
|
||||||
|
// if md5: NOP NOP MD5SIG 18 md5sig(16)
|
||||||
|
// if mss: MSS 4 mss(2)
|
||||||
|
// if ts and sack_advertise:
|
||||||
|
// SACK 2 TIMESTAMP 2 timestamp(8)
|
||||||
|
// elif ts: NOP NOP TIMESTAMP 10 timestamp(8)
|
||||||
|
// elif sack: NOP NOP SACK 2
|
||||||
|
// if wscale: NOP WINDOW 3 ws(1)
|
||||||
|
// if sack_blocks: NOP NOP SACK ((2 + (#blocks * 8))
|
||||||
|
// [for each block] start_seq(4) end_seq(4)
|
||||||
|
// if fastopen_cookie:
|
||||||
|
// if exp: EXP (4 + len(cookie)) FASTOPEN_MAGIC(2)
|
||||||
|
// else: FASTOPEN (2 + len(cookie))
|
||||||
|
// cookie(variable) [padding to four bytes]
|
||||||
|
//
|
||||||
|
options := getOptions()
|
||||||
|
|
||||||
|
// Always encode the mss.
|
||||||
|
offset := header.EncodeMSSOption(uint32(opts.MSS), options)
|
||||||
|
|
||||||
|
// Special ordering is required here. If both TS and SACK are enabled,
|
||||||
|
// then the SACK option precedes TS, with no padding. If they are
|
||||||
|
// enabled individually, then we see padding before the option.
|
||||||
|
if opts.TS && opts.SACKPermitted {
|
||||||
|
offset += header.EncodeSACKPermittedOption(options[offset:])
|
||||||
|
offset += header.EncodeTSOption(opts.TSVal, opts.TSEcr, options[offset:])
|
||||||
|
} else if opts.TS {
|
||||||
|
offset += header.EncodeNOP(options[offset:])
|
||||||
|
offset += header.EncodeNOP(options[offset:])
|
||||||
|
offset += header.EncodeTSOption(opts.TSVal, opts.TSEcr, options[offset:])
|
||||||
|
} else if opts.SACKPermitted {
|
||||||
|
offset += header.EncodeNOP(options[offset:])
|
||||||
|
offset += header.EncodeNOP(options[offset:])
|
||||||
|
offset += header.EncodeSACKPermittedOption(options[offset:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the WS option.
|
||||||
|
if opts.WS >= 0 {
|
||||||
|
offset += header.EncodeNOP(options[offset:])
|
||||||
|
offset += header.EncodeWSOption(opts.WS, options[offset:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Padding to the end; note that this never apply unless we add a
|
||||||
|
// fastopen option, we always expect the offset to remain the same.
|
||||||
|
if delta := header.AddTCPOptionPadding(options, offset); delta != 0 {
|
||||||
|
panic("unexpected option encoding")
|
||||||
|
}
|
||||||
|
|
||||||
|
return options[:offset]
|
||||||
|
}
|
||||||
|
|
||||||
// 封装 sendTCP ,发送 syn 报文
|
// 封装 sendTCP ,发送 syn 报文
|
||||||
func sendSynTCP(r *stack.Route, id stack.TransportEndpointID, flags byte,
|
func sendSynTCP(r *stack.Route, id stack.TransportEndpointID, flags byte,
|
||||||
seq, ack seqnum.Value, rcvWnd seqnum.Size, opts header.TCPSynOptions) *tcpip.Error {
|
seq, ack seqnum.Value, rcvWnd seqnum.Size, opts header.TCPSynOptions) *tcpip.Error {
|
||||||
|
if opts.MSS == 0 {
|
||||||
options := []byte{}
|
opts.MSS = uint16(r.MTU() - header.TCPMinimumSize)
|
||||||
err := sendTCP(r, id, buffer.VectorisedView{}, 0, flags, seq, ack, rcvWnd, options)
|
}
|
||||||
|
options := makeSynOptions(opts)
|
||||||
|
err := sendTCP(r, id, buffer.VectorisedView{}, r.DefaultTTL(), flags, seq, ack, rcvWnd, options)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +309,50 @@ func sendSynTCP(r *stack.Route, id stack.TransportEndpointID, flags byte,
|
|||||||
func sendTCP(r *stack.Route, id stack.TransportEndpointID, data buffer.VectorisedView, ttl uint8, flags byte,
|
func sendTCP(r *stack.Route, id stack.TransportEndpointID, data buffer.VectorisedView, ttl uint8, flags byte,
|
||||||
seq, ack seqnum.Value, rcvWnd seqnum.Size, opts []byte) *tcpip.Error {
|
seq, ack seqnum.Value, rcvWnd seqnum.Size, opts []byte) *tcpip.Error {
|
||||||
log.Println("进行一个报文的发送")
|
log.Println("进行一个报文的发送")
|
||||||
return nil
|
optLen := len(opts)
|
||||||
|
// Allocate a buffer for the TCP header.
|
||||||
|
hdr := buffer.NewPrependable(header.TCPMinimumSize + int(r.MaxHeaderLength()) + optLen)
|
||||||
|
|
||||||
|
if rcvWnd > 0xffff {
|
||||||
|
rcvWnd = 0xffff
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the header.
|
||||||
|
tcp := header.TCP(hdr.Prepend(header.TCPMinimumSize + optLen))
|
||||||
|
tcp.Encode(&header.TCPFields{
|
||||||
|
SrcPort: id.LocalPort,
|
||||||
|
DstPort: id.RemotePort,
|
||||||
|
SeqNum: uint32(seq),
|
||||||
|
AckNum: uint32(ack),
|
||||||
|
DataOffset: uint8(header.TCPMinimumSize + optLen),
|
||||||
|
Flags: flags,
|
||||||
|
WindowSize: uint16(rcvWnd),
|
||||||
|
})
|
||||||
|
copy(tcp[header.TCPMinimumSize:], opts)
|
||||||
|
|
||||||
|
// Only calculate the checksum if offloading isn't supported.
|
||||||
|
if r.Capabilities()&stack.CapabilityChecksumOffload == 0 {
|
||||||
|
length := uint16(hdr.UsedLength() + data.Size())
|
||||||
|
// tcp伪首部校验和的计算
|
||||||
|
xsum := r.PseudoHeaderChecksum(ProtocolNumber)
|
||||||
|
for _, v := range data.Views() {
|
||||||
|
xsum = header.Checksum(v, xsum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tcp的可靠性:校验和的计算,用于检测损伤的报文段
|
||||||
|
tcp.SetChecksum(^tcp.CalculateChecksum(xsum, length))
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Stats().TCP.SegmentsSent.Increment()
|
||||||
|
if (flags & flagRst) != 0 {
|
||||||
|
r.Stats().TCP.ResetsSent.Increment()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("send tcp %s segment to %s, seq: %d, ack: %d, rcvWnd: %d",
|
||||||
|
flagString(flags), fmt.Sprintf("%s:%d", id.RemoteAddress, id.RemotePort),
|
||||||
|
seq, ack, rcvWnd)
|
||||||
|
|
||||||
|
return r.WritePacket(hdr, data, ProtocolNumber, ttl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// protocolMainLoop 是TCP协议的主循环。它在自己的goroutine中运行,负责握手、发送段和处理收到的段
|
// protocolMainLoop 是TCP协议的主循环。它在自己的goroutine中运行,负责握手、发送段和处理收到的段
|
||||||
|
|||||||
Reference in New Issue
Block a user