mirror of
https://github.com/fumiama/WireGold.git
synced 2025-09-26 19:21:11 +08:00
159 lines
3.8 KiB
Go
159 lines
3.8 KiB
Go
package link
|
|
|
|
import (
|
|
crand "crypto/rand"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"math/rand"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/fumiama/WireGold/config"
|
|
"github.com/fumiama/WireGold/gold/head"
|
|
"github.com/fumiama/WireGold/internal/bin"
|
|
base14 "github.com/fumiama/go-base16384"
|
|
"github.com/fumiama/orbyte/pbuf"
|
|
)
|
|
|
|
var (
|
|
ErrDropBigDontFragPkt = errors.New("drop big don't fragmnet packet")
|
|
ErrTTL = errors.New("ttl exceeded")
|
|
)
|
|
|
|
func randseq(i uint16) uint32 {
|
|
var buf [4]byte
|
|
_, _ = crand.Read(buf[:2])
|
|
binary.BigEndian.PutUint16(buf[2:4], i)
|
|
return binary.BigEndian.Uint32(buf[:])
|
|
}
|
|
|
|
// WritePacket 基于 data 向 peer 发包
|
|
//
|
|
// data 可为空, 因为不保证可达所以不返回错误。
|
|
func (l *Link) WritePacket(proto uint8, data []byte, ttl uint8) {
|
|
teatype := l.randkeyidx()
|
|
sndcnt := uint16(l.incgetsndcnt())
|
|
mtu := l.mtu
|
|
if l.mturandomrange > 0 {
|
|
mtu -= uint16(rand.Intn(int(l.mturandomrange)))
|
|
}
|
|
if config.ShowDebugLog {
|
|
logrus.Debugln("[send] write mtu:", mtu, ", addt:", sndcnt&0x07ff, ", key index:", teatype, ", data len:", len(data))
|
|
}
|
|
pb := head.NewPacketBuilder().
|
|
Src(l.me.me, l.me.srcport).Dst(l.peerip, l.me.dstport).
|
|
Proto(proto).TTL(ttl).With(data)
|
|
if l.usezstd {
|
|
pb.Zstd()
|
|
}
|
|
pb = pb.Hash()
|
|
var pktb *head.PacketBuilder
|
|
if l.keys[0] == nil {
|
|
pktb = pb.Plain(teatype, sndcnt&0x07ff)
|
|
} else {
|
|
pktb = pb.Seal(l.keys[teatype], teatype, sndcnt&0x07ff)
|
|
}
|
|
bs := pktb.Split(int(mtu), false)
|
|
pktb.Destroy()
|
|
if config.ShowDebugLog {
|
|
logrus.Debugln("[send] split packet into", len(bs), "parts")
|
|
}
|
|
for _, b := range bs { //TODO: impl. nofrag
|
|
go l.write2peer(head.BuildPacketFromBytes(b), randseq(sndcnt))
|
|
b.ManualDestroy()
|
|
}
|
|
}
|
|
|
|
// write2peer 计算 xor + b14 后向 peer 发包
|
|
//
|
|
// 因为不保证可达所以不返回错误。
|
|
func (l *Link) write2peer(b pbuf.Bytes, seq uint32) {
|
|
defer b.ManualDestroy()
|
|
if l.doublepacket {
|
|
err := l.write2peer1(b, seq)
|
|
if err != nil {
|
|
if config.ShowDebugLog {
|
|
logrus.Warnln("[send] double wr2peer", l.peerip, "err:", err)
|
|
}
|
|
}
|
|
}
|
|
err := l.write2peer1(b, seq)
|
|
if err != nil {
|
|
if config.ShowDebugLog {
|
|
logrus.Warnln("[send] wr2peer", l.peerip, "err:", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// write2peer1 计算 xor + b14 后向 peer 发一个包
|
|
func (l *Link) write2peer1(b pbuf.Bytes, seq uint32) (err error) {
|
|
peerep := l.endpoint
|
|
if bin.IsNilInterface(peerep) {
|
|
return errors.New("nil endpoint of " + l.peerip.String())
|
|
}
|
|
|
|
conn := l.me.conn
|
|
if conn == nil {
|
|
return io.ErrClosedPipe
|
|
}
|
|
isnewb := false
|
|
b.V(func(data []byte) {
|
|
if config.ShowDebugLog {
|
|
bound := 64
|
|
endl := "..."
|
|
if len(data) < bound {
|
|
bound = len(data)
|
|
endl = "."
|
|
}
|
|
logrus.Debugln("[send] crc seq", fmt.Sprintf("%08x", seq), "raw data bytes", hex.EncodeToString(data[:bound]), endl)
|
|
}
|
|
b = pbuf.ParseBytes(l.me.xorenc(data, seq)...).Ignore()
|
|
isnewb = true
|
|
})
|
|
if config.ShowDebugLog {
|
|
bound := 64
|
|
endl := "..."
|
|
if b.Len() < bound {
|
|
bound = b.Len()
|
|
endl = "."
|
|
}
|
|
b.V(func(b []byte) {
|
|
logrus.Debugln("[send] crc seq", fmt.Sprintf("%08x", seq), "xored data bytes", hex.EncodeToString(b[:bound]), endl)
|
|
})
|
|
}
|
|
if l.me.base14 {
|
|
b.V(func(data []byte) {
|
|
old := b
|
|
b = pbuf.ParseBytes(base14.Encode(data)...).Ignore()
|
|
if isnewb {
|
|
old.ManualDestroy()
|
|
}
|
|
isnewb = true
|
|
if config.ShowDebugLog {
|
|
bound := 64
|
|
endl := "..."
|
|
if b.Len() < bound {
|
|
bound = b.Len()
|
|
endl = "."
|
|
}
|
|
b.V(func(b []byte) {
|
|
logrus.Debugln("[send] crc seq", fmt.Sprintf("%08x", seq), "b14ed data bytes", hex.EncodeToString(b[:bound]), endl)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
b.V(func(b []byte) {
|
|
if config.ShowDebugLog {
|
|
logrus.Debugln("[send] crc seq", fmt.Sprintf("%08x", seq), "write", len(b), "bytes data from ep", conn.LocalAddr(), "to", peerep)
|
|
}
|
|
_, err = conn.WriteToPeer(b, peerep)
|
|
})
|
|
if isnewb {
|
|
b.ManualDestroy()
|
|
}
|
|
return
|
|
}
|