global: buff -> buf
This always struck me as kind of weird and non-standard. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									7d327ed35a
								
							
						
					
					
						commit
						0ad14a89f5
					
				@ -204,11 +204,11 @@ again:
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *StdNetBind) makeReceiveIPv4(pc *ipv4.PacketConn, conn *net.UDPConn) ReceiveFunc {
 | 
			
		||||
	return func(buffs [][]byte, sizes []int, eps []Endpoint) (n int, err error) {
 | 
			
		||||
	return func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) {
 | 
			
		||||
		msgs := s.ipv4MsgsPool.Get().(*[]ipv4.Message)
 | 
			
		||||
		defer s.ipv4MsgsPool.Put(msgs)
 | 
			
		||||
		for i := range buffs {
 | 
			
		||||
			(*msgs)[i].Buffers[0] = buffs[i]
 | 
			
		||||
		for i := range bufs {
 | 
			
		||||
			(*msgs)[i].Buffers[0] = bufs[i]
 | 
			
		||||
		}
 | 
			
		||||
		var numMsgs int
 | 
			
		||||
		if runtime.GOOS == "linux" {
 | 
			
		||||
@ -237,11 +237,11 @@ func (s *StdNetBind) makeReceiveIPv4(pc *ipv4.PacketConn, conn *net.UDPConn) Rec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *StdNetBind) makeReceiveIPv6(pc *ipv6.PacketConn, conn *net.UDPConn) ReceiveFunc {
 | 
			
		||||
	return func(buffs [][]byte, sizes []int, eps []Endpoint) (n int, err error) {
 | 
			
		||||
	return func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) {
 | 
			
		||||
		msgs := s.ipv4MsgsPool.Get().(*[]ipv6.Message)
 | 
			
		||||
		defer s.ipv4MsgsPool.Put(msgs)
 | 
			
		||||
		for i := range buffs {
 | 
			
		||||
			(*msgs)[i].Buffers[0] = buffs[i]
 | 
			
		||||
		for i := range bufs {
 | 
			
		||||
			(*msgs)[i].Buffers[0] = bufs[i]
 | 
			
		||||
		}
 | 
			
		||||
		var numMsgs int
 | 
			
		||||
		if runtime.GOOS == "linux" {
 | 
			
		||||
@ -301,7 +301,7 @@ func (s *StdNetBind) Close() error {
 | 
			
		||||
	return err2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *StdNetBind) Send(buffs [][]byte, endpoint Endpoint) error {
 | 
			
		||||
func (s *StdNetBind) Send(bufs [][]byte, endpoint Endpoint) error {
 | 
			
		||||
	s.mu.Lock()
 | 
			
		||||
	blackhole := s.blackhole4
 | 
			
		||||
	conn := s.ipv4
 | 
			
		||||
@ -327,21 +327,21 @@ func (s *StdNetBind) Send(buffs [][]byte, endpoint Endpoint) error {
 | 
			
		||||
		return syscall.EAFNOSUPPORT
 | 
			
		||||
	}
 | 
			
		||||
	if is6 {
 | 
			
		||||
		return s.send6(conn, pc6, endpoint, buffs)
 | 
			
		||||
		return s.send6(conn, pc6, endpoint, bufs)
 | 
			
		||||
	} else {
 | 
			
		||||
		return s.send4(conn, pc4, endpoint, buffs)
 | 
			
		||||
		return s.send4(conn, pc4, endpoint, bufs)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *StdNetBind) send4(conn *net.UDPConn, pc *ipv4.PacketConn, ep Endpoint, buffs [][]byte) error {
 | 
			
		||||
func (s *StdNetBind) send4(conn *net.UDPConn, pc *ipv4.PacketConn, ep Endpoint, bufs [][]byte) error {
 | 
			
		||||
	ua := s.udpAddrPool.Get().(*net.UDPAddr)
 | 
			
		||||
	as4 := ep.DstIP().As4()
 | 
			
		||||
	copy(ua.IP, as4[:])
 | 
			
		||||
	ua.IP = ua.IP[:4]
 | 
			
		||||
	ua.Port = int(ep.(*StdNetEndpoint).Port())
 | 
			
		||||
	msgs := s.ipv4MsgsPool.Get().(*[]ipv4.Message)
 | 
			
		||||
	for i, buff := range buffs {
 | 
			
		||||
		(*msgs)[i].Buffers[0] = buff
 | 
			
		||||
	for i, buf := range bufs {
 | 
			
		||||
		(*msgs)[i].Buffers[0] = buf
 | 
			
		||||
		(*msgs)[i].Addr = ua
 | 
			
		||||
		setSrcControl(&(*msgs)[i].OOB, ep.(*StdNetEndpoint))
 | 
			
		||||
	}
 | 
			
		||||
@ -352,15 +352,15 @@ func (s *StdNetBind) send4(conn *net.UDPConn, pc *ipv4.PacketConn, ep Endpoint,
 | 
			
		||||
	)
 | 
			
		||||
	if runtime.GOOS == "linux" {
 | 
			
		||||
		for {
 | 
			
		||||
			n, err = pc.WriteBatch((*msgs)[start:len(buffs)], 0)
 | 
			
		||||
			if err != nil || n == len((*msgs)[start:len(buffs)]) {
 | 
			
		||||
			n, err = pc.WriteBatch((*msgs)[start:len(bufs)], 0)
 | 
			
		||||
			if err != nil || n == len((*msgs)[start:len(bufs)]) {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			start += n
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for i, buff := range buffs {
 | 
			
		||||
			_, _, err = conn.WriteMsgUDP(buff, (*msgs)[i].OOB, ua)
 | 
			
		||||
		for i, buf := range bufs {
 | 
			
		||||
			_, _, err = conn.WriteMsgUDP(buf, (*msgs)[i].OOB, ua)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
@ -371,15 +371,15 @@ func (s *StdNetBind) send4(conn *net.UDPConn, pc *ipv4.PacketConn, ep Endpoint,
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *StdNetBind) send6(conn *net.UDPConn, pc *ipv6.PacketConn, ep Endpoint, buffs [][]byte) error {
 | 
			
		||||
func (s *StdNetBind) send6(conn *net.UDPConn, pc *ipv6.PacketConn, ep Endpoint, bufs [][]byte) error {
 | 
			
		||||
	ua := s.udpAddrPool.Get().(*net.UDPAddr)
 | 
			
		||||
	as16 := ep.DstIP().As16()
 | 
			
		||||
	copy(ua.IP, as16[:])
 | 
			
		||||
	ua.IP = ua.IP[:16]
 | 
			
		||||
	ua.Port = int(ep.(*StdNetEndpoint).Port())
 | 
			
		||||
	msgs := s.ipv6MsgsPool.Get().(*[]ipv6.Message)
 | 
			
		||||
	for i, buff := range buffs {
 | 
			
		||||
		(*msgs)[i].Buffers[0] = buff
 | 
			
		||||
	for i, buf := range bufs {
 | 
			
		||||
		(*msgs)[i].Buffers[0] = buf
 | 
			
		||||
		(*msgs)[i].Addr = ua
 | 
			
		||||
		setSrcControl(&(*msgs)[i].OOB, ep.(*StdNetEndpoint))
 | 
			
		||||
	}
 | 
			
		||||
@ -390,15 +390,15 @@ func (s *StdNetBind) send6(conn *net.UDPConn, pc *ipv6.PacketConn, ep Endpoint,
 | 
			
		||||
	)
 | 
			
		||||
	if runtime.GOOS == "linux" {
 | 
			
		||||
		for {
 | 
			
		||||
			n, err = pc.WriteBatch((*msgs)[start:len(buffs)], 0)
 | 
			
		||||
			if err != nil || n == len((*msgs)[start:len(buffs)]) {
 | 
			
		||||
			n, err = pc.WriteBatch((*msgs)[start:len(bufs)], 0)
 | 
			
		||||
			if err != nil || n == len((*msgs)[start:len(bufs)]) {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			start += n
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for i, buff := range buffs {
 | 
			
		||||
			_, _, err = conn.WriteMsgUDP(buff, (*msgs)[i].OOB, ua)
 | 
			
		||||
		for i, buf := range bufs {
 | 
			
		||||
			_, _, err = conn.WriteMsgUDP(buf, (*msgs)[i].OOB, ua)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -9,14 +9,14 @@ func TestStdNetBindReceiveFuncAfterClose(t *testing.T) {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	bind.Close()
 | 
			
		||||
	buffs := make([][]byte, 1)
 | 
			
		||||
	buffs[0] = make([]byte, 1)
 | 
			
		||||
	bufs := make([][]byte, 1)
 | 
			
		||||
	bufs[0] = make([]byte, 1)
 | 
			
		||||
	sizes := make([]int, 1)
 | 
			
		||||
	eps := make([]Endpoint, 1)
 | 
			
		||||
	for _, fn := range fns {
 | 
			
		||||
		// The ReceiveFuncs must not access conn-related fields on StdNetBind
 | 
			
		||||
		// unguarded. Close() nils the conn-related fields resulting in a panic
 | 
			
		||||
		// if they violate the mutex.
 | 
			
		||||
		fn(buffs, sizes, eps)
 | 
			
		||||
		fn(bufs, sizes, eps)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -416,19 +416,19 @@ retry:
 | 
			
		||||
	return n, &ep, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (bind *WinRingBind) receiveIPv4(buffs [][]byte, sizes []int, eps []Endpoint) (int, error) {
 | 
			
		||||
func (bind *WinRingBind) receiveIPv4(bufs [][]byte, sizes []int, eps []Endpoint) (int, error) {
 | 
			
		||||
	bind.mu.RLock()
 | 
			
		||||
	defer bind.mu.RUnlock()
 | 
			
		||||
	n, ep, err := bind.v4.Receive(buffs[0], &bind.isOpen)
 | 
			
		||||
	n, ep, err := bind.v4.Receive(bufs[0], &bind.isOpen)
 | 
			
		||||
	sizes[0] = n
 | 
			
		||||
	eps[0] = ep
 | 
			
		||||
	return 1, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (bind *WinRingBind) receiveIPv6(buffs [][]byte, sizes []int, eps []Endpoint) (int, error) {
 | 
			
		||||
func (bind *WinRingBind) receiveIPv6(bufs [][]byte, sizes []int, eps []Endpoint) (int, error) {
 | 
			
		||||
	bind.mu.RLock()
 | 
			
		||||
	defer bind.mu.RUnlock()
 | 
			
		||||
	n, ep, err := bind.v6.Receive(buffs[0], &bind.isOpen)
 | 
			
		||||
	n, ep, err := bind.v6.Receive(bufs[0], &bind.isOpen)
 | 
			
		||||
	sizes[0] = n
 | 
			
		||||
	eps[0] = ep
 | 
			
		||||
	return 1, err
 | 
			
		||||
@ -486,14 +486,14 @@ func (bind *afWinRingBind) Send(buf []byte, nend *WinRingEndpoint, isOpen *atomi
 | 
			
		||||
	return winrio.SendEx(bind.rq, dataBuffer, 1, nil, addressBuffer, nil, nil, 0, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (bind *WinRingBind) Send(buffs [][]byte, endpoint Endpoint) error {
 | 
			
		||||
func (bind *WinRingBind) Send(bufs [][]byte, endpoint Endpoint) error {
 | 
			
		||||
	nend, ok := endpoint.(*WinRingEndpoint)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ErrWrongEndpointType
 | 
			
		||||
	}
 | 
			
		||||
	bind.mu.RLock()
 | 
			
		||||
	defer bind.mu.RUnlock()
 | 
			
		||||
	for _, buf := range buffs {
 | 
			
		||||
	for _, buf := range bufs {
 | 
			
		||||
		switch nend.family {
 | 
			
		||||
		case windows.AF_INET:
 | 
			
		||||
			if bind.v4.blackhole {
 | 
			
		||||
 | 
			
		||||
@ -94,12 +94,12 @@ func (c *ChannelBind) BatchSize() int { return 1 }
 | 
			
		||||
func (c *ChannelBind) SetMark(mark uint32) error { return nil }
 | 
			
		||||
 | 
			
		||||
func (c *ChannelBind) makeReceiveFunc(ch chan []byte) conn.ReceiveFunc {
 | 
			
		||||
	return func(buffs [][]byte, sizes []int, eps []conn.Endpoint) (n int, err error) {
 | 
			
		||||
	return func(bufs [][]byte, sizes []int, eps []conn.Endpoint) (n int, err error) {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-c.closeSignal:
 | 
			
		||||
			return 0, net.ErrClosed
 | 
			
		||||
		case rx := <-ch:
 | 
			
		||||
			copied := copy(buffs[0], rx)
 | 
			
		||||
			copied := copy(bufs[0], rx)
 | 
			
		||||
			sizes[0] = copied
 | 
			
		||||
			eps[0] = c.target6
 | 
			
		||||
			return 1, nil
 | 
			
		||||
@ -107,8 +107,8 @@ func (c *ChannelBind) makeReceiveFunc(ch chan []byte) conn.ReceiveFunc {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ChannelBind) Send(buffs [][]byte, ep conn.Endpoint) error {
 | 
			
		||||
	for _, b := range buffs {
 | 
			
		||||
func (c *ChannelBind) Send(bufs [][]byte, ep conn.Endpoint) error {
 | 
			
		||||
	for _, b := range bufs {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-c.closeSignal:
 | 
			
		||||
			return net.ErrClosed
 | 
			
		||||
 | 
			
		||||
@ -45,9 +45,9 @@ type Bind interface {
 | 
			
		||||
	// This mark is passed to the kernel as the socket option SO_MARK.
 | 
			
		||||
	SetMark(mark uint32) error
 | 
			
		||||
 | 
			
		||||
	// Send writes one or more packets in buffs to address ep. The length of
 | 
			
		||||
	// buffs must not exceed BatchSize().
 | 
			
		||||
	Send(buffs [][]byte, ep Endpoint) error
 | 
			
		||||
	// Send writes one or more packets in bufs to address ep. The length of
 | 
			
		||||
	// bufs must not exceed BatchSize().
 | 
			
		||||
	Send(bufs [][]byte, ep Endpoint) error
 | 
			
		||||
 | 
			
		||||
	// ParseEndpoint creates a new endpoint from a string.
 | 
			
		||||
	ParseEndpoint(s string) (Endpoint, error)
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ import (
 | 
			
		||||
 | 
			
		||||
func TestPrettyName(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		recvFunc ReceiveFunc = func(buffs [][]byte, sizes []int, eps []Endpoint) (n int, err error) { return }
 | 
			
		||||
		recvFunc ReceiveFunc = func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) { return }
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	const want = "TestPrettyName"
 | 
			
		||||
 | 
			
		||||
@ -26,21 +26,21 @@ func (b *DummyBind) SetMark(v uint32) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *DummyBind) ReceiveIPv6(buff []byte) (int, conn.Endpoint, error) {
 | 
			
		||||
func (b *DummyBind) ReceiveIPv6(buf []byte) (int, conn.Endpoint, error) {
 | 
			
		||||
	datagram, ok := <-b.in6
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, nil, errors.New("closed")
 | 
			
		||||
	}
 | 
			
		||||
	copy(buff, datagram.msg)
 | 
			
		||||
	copy(buf, datagram.msg)
 | 
			
		||||
	return len(datagram.msg), datagram.endpoint, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *DummyBind) ReceiveIPv4(buff []byte) (int, conn.Endpoint, error) {
 | 
			
		||||
func (b *DummyBind) ReceiveIPv4(buf []byte) (int, conn.Endpoint, error) {
 | 
			
		||||
	datagram, ok := <-b.in4
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, nil, errors.New("closed")
 | 
			
		||||
	}
 | 
			
		||||
	copy(buff, datagram.msg)
 | 
			
		||||
	copy(buf, datagram.msg)
 | 
			
		||||
	return len(datagram.msg), datagram.endpoint, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -51,6 +51,6 @@ func (b *DummyBind) Close() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *DummyBind) Send(buff []byte, end conn.Endpoint) error {
 | 
			
		||||
func (b *DummyBind) Send(buf []byte, end conn.Endpoint) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -428,7 +428,7 @@ func (b *fakeBindSized) Open(port uint16) (fns []conn.ReceiveFunc, actualPort ui
 | 
			
		||||
}
 | 
			
		||||
func (b *fakeBindSized) Close() error                                  { return nil }
 | 
			
		||||
func (b *fakeBindSized) SetMark(mark uint32) error                     { return nil }
 | 
			
		||||
func (b *fakeBindSized) Send(buffs [][]byte, ep conn.Endpoint) error   { return nil }
 | 
			
		||||
func (b *fakeBindSized) Send(bufs [][]byte, ep conn.Endpoint) error    { return nil }
 | 
			
		||||
func (b *fakeBindSized) ParseEndpoint(s string) (conn.Endpoint, error) { return nil, nil }
 | 
			
		||||
func (b *fakeBindSized) BatchSize() int                                { return b.size }
 | 
			
		||||
 | 
			
		||||
@ -437,15 +437,15 @@ type fakeTUNDeviceSized struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *fakeTUNDeviceSized) File() *os.File { return nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) Read(buffs [][]byte, sizes []int, offset int) (n int, err error) {
 | 
			
		||||
func (t *fakeTUNDeviceSized) Read(bufs [][]byte, sizes []int, offset int) (n int, err error) {
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
func (t *fakeTUNDeviceSized) Write(buffs [][]byte, offset int) (int, error) { return 0, nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) MTU() (int, error)                             { return 0, nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) Name() (string, error)                         { return "", nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) Events() <-chan tun.Event                      { return nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) Close() error                                  { return nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) BatchSize() int                                { return t.size }
 | 
			
		||||
func (t *fakeTUNDeviceSized) Write(bufs [][]byte, offset int) (int, error) { return 0, nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) MTU() (int, error)                            { return 0, nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) Name() (string, error)                        { return "", nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) Events() <-chan tun.Event                     { return nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) Close() error                                 { return nil }
 | 
			
		||||
func (t *fakeTUNDeviceSized) BatchSize() int                               { return t.size }
 | 
			
		||||
 | 
			
		||||
func TestBatchSize(t *testing.T) {
 | 
			
		||||
	d := Device{}
 | 
			
		||||
 | 
			
		||||
@ -80,8 +80,8 @@ func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.Receive
 | 
			
		||||
	// receive datagrams until conn is closed
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		buffsArrs   = make([]*[MaxMessageSize]byte, maxBatchSize)
 | 
			
		||||
		buffs       = make([][]byte, maxBatchSize)
 | 
			
		||||
		bufsArrs    = make([]*[MaxMessageSize]byte, maxBatchSize)
 | 
			
		||||
		bufs        = make([][]byte, maxBatchSize)
 | 
			
		||||
		err         error
 | 
			
		||||
		sizes       = make([]int, maxBatchSize)
 | 
			
		||||
		count       int
 | 
			
		||||
@ -90,21 +90,21 @@ func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.Receive
 | 
			
		||||
		elemsByPeer = make(map[*Peer]*[]*QueueInboundElement, maxBatchSize)
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for i := range buffsArrs {
 | 
			
		||||
		buffsArrs[i] = device.GetMessageBuffer()
 | 
			
		||||
		buffs[i] = buffsArrs[i][:]
 | 
			
		||||
	for i := range bufsArrs {
 | 
			
		||||
		bufsArrs[i] = device.GetMessageBuffer()
 | 
			
		||||
		bufs[i] = bufsArrs[i][:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		for i := 0; i < maxBatchSize; i++ {
 | 
			
		||||
			if buffsArrs[i] != nil {
 | 
			
		||||
				device.PutMessageBuffer(buffsArrs[i])
 | 
			
		||||
			if bufsArrs[i] != nil {
 | 
			
		||||
				device.PutMessageBuffer(bufsArrs[i])
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		count, err = recv(buffs, sizes, endpoints)
 | 
			
		||||
		count, err = recv(bufs, sizes, endpoints)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if errors.Is(err, net.ErrClosed) {
 | 
			
		||||
				return
 | 
			
		||||
@ -130,7 +130,7 @@ func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.Receive
 | 
			
		||||
 | 
			
		||||
			// check size of packet
 | 
			
		||||
 | 
			
		||||
			packet := buffsArrs[i][:size]
 | 
			
		||||
			packet := bufsArrs[i][:size]
 | 
			
		||||
			msgType := binary.LittleEndian.Uint32(packet[:4])
 | 
			
		||||
 | 
			
		||||
			switch msgType {
 | 
			
		||||
@ -166,7 +166,7 @@ func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.Receive
 | 
			
		||||
				peer := value.peer
 | 
			
		||||
				elem := device.GetInboundElement()
 | 
			
		||||
				elem.packet = packet
 | 
			
		||||
				elem.buffer = buffsArrs[i]
 | 
			
		||||
				elem.buffer = bufsArrs[i]
 | 
			
		||||
				elem.keypair = keypair
 | 
			
		||||
				elem.endpoint = endpoints[i]
 | 
			
		||||
				elem.counter = 0
 | 
			
		||||
@ -179,8 +179,8 @@ func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.Receive
 | 
			
		||||
					elemsByPeer[peer] = elemsForPeer
 | 
			
		||||
				}
 | 
			
		||||
				*elemsForPeer = append(*elemsForPeer, elem)
 | 
			
		||||
				buffsArrs[i] = device.GetMessageBuffer()
 | 
			
		||||
				buffs[i] = buffsArrs[i][:]
 | 
			
		||||
				bufsArrs[i] = device.GetMessageBuffer()
 | 
			
		||||
				bufs[i] = bufsArrs[i][:]
 | 
			
		||||
				continue
 | 
			
		||||
 | 
			
		||||
			// otherwise it is a fixed size & handshake related packet
 | 
			
		||||
@ -208,12 +208,12 @@ func (device *Device) RoutineReceiveIncoming(maxBatchSize int, recv conn.Receive
 | 
			
		||||
			select {
 | 
			
		||||
			case device.queue.handshake.c <- QueueHandshakeElement{
 | 
			
		||||
				msgType:  msgType,
 | 
			
		||||
				buffer:   buffsArrs[i],
 | 
			
		||||
				buffer:   bufsArrs[i],
 | 
			
		||||
				packet:   packet,
 | 
			
		||||
				endpoint: endpoints[i],
 | 
			
		||||
			}:
 | 
			
		||||
				buffsArrs[i] = device.GetMessageBuffer()
 | 
			
		||||
				buffs[i] = buffsArrs[i][:]
 | 
			
		||||
				bufsArrs[i] = device.GetMessageBuffer()
 | 
			
		||||
				bufs[i] = bufsArrs[i][:]
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -435,7 +435,7 @@ func (peer *Peer) RoutineSequentialReceiver(maxBatchSize int) {
 | 
			
		||||
	}()
 | 
			
		||||
	device.log.Verbosef("%v - Routine: sequential receiver - started", peer)
 | 
			
		||||
 | 
			
		||||
	buffs := make([][]byte, 0, maxBatchSize)
 | 
			
		||||
	bufs := make([][]byte, 0, maxBatchSize)
 | 
			
		||||
 | 
			
		||||
	for elems := range peer.queue.inbound.c {
 | 
			
		||||
		if elems == nil {
 | 
			
		||||
@ -507,10 +507,10 @@ func (peer *Peer) RoutineSequentialReceiver(maxBatchSize int) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			buffs = append(buffs, elem.buffer[:MessageTransportOffsetContent+len(elem.packet)])
 | 
			
		||||
			bufs = append(bufs, elem.buffer[:MessageTransportOffsetContent+len(elem.packet)])
 | 
			
		||||
		}
 | 
			
		||||
		if len(buffs) > 0 {
 | 
			
		||||
			_, err := device.tun.device.Write(buffs, MessageTransportOffsetContent)
 | 
			
		||||
		if len(bufs) > 0 {
 | 
			
		||||
			_, err := device.tun.device.Write(bufs, MessageTransportOffsetContent)
 | 
			
		||||
			if err != nil && !device.isClosed() {
 | 
			
		||||
				device.log.Errorf("Failed to write packets to TUN device: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
@ -519,7 +519,7 @@ func (peer *Peer) RoutineSequentialReceiver(maxBatchSize int) {
 | 
			
		||||
			device.PutMessageBuffer(elem.buffer)
 | 
			
		||||
			device.PutInboundElement(elem)
 | 
			
		||||
		}
 | 
			
		||||
		buffs = buffs[:0]
 | 
			
		||||
		bufs = bufs[:0]
 | 
			
		||||
		device.PutInboundElementsSlice(elems)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -120,8 +120,8 @@ func (peer *Peer) SendHandshakeInitiation(isRetry bool) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var buff [MessageInitiationSize]byte
 | 
			
		||||
	writer := bytes.NewBuffer(buff[:0])
 | 
			
		||||
	var buf [MessageInitiationSize]byte
 | 
			
		||||
	writer := bytes.NewBuffer(buf[:0])
 | 
			
		||||
	binary.Write(writer, binary.LittleEndian, msg)
 | 
			
		||||
	packet := writer.Bytes()
 | 
			
		||||
	peer.cookieGenerator.AddMacs(packet)
 | 
			
		||||
@ -151,8 +151,8 @@ func (peer *Peer) SendHandshakeResponse() error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var buff [MessageResponseSize]byte
 | 
			
		||||
	writer := bytes.NewBuffer(buff[:0])
 | 
			
		||||
	var buf [MessageResponseSize]byte
 | 
			
		||||
	writer := bytes.NewBuffer(buf[:0])
 | 
			
		||||
	binary.Write(writer, binary.LittleEndian, response)
 | 
			
		||||
	packet := writer.Bytes()
 | 
			
		||||
	peer.cookieGenerator.AddMacs(packet)
 | 
			
		||||
@ -185,8 +185,8 @@ func (device *Device) SendHandshakeCookie(initiatingElem *QueueHandshakeElement)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var buff [MessageCookieReplySize]byte
 | 
			
		||||
	writer := bytes.NewBuffer(buff[:0])
 | 
			
		||||
	var buf [MessageCookieReplySize]byte
 | 
			
		||||
	writer := bytes.NewBuffer(buf[:0])
 | 
			
		||||
	binary.Write(writer, binary.LittleEndian, reply)
 | 
			
		||||
	// TODO: allocation could be avoided
 | 
			
		||||
	device.net.bind.Send([][]byte{writer.Bytes()}, initiatingElem.endpoint)
 | 
			
		||||
@ -217,7 +217,7 @@ func (device *Device) RoutineReadFromTUN() {
 | 
			
		||||
		batchSize   = device.BatchSize()
 | 
			
		||||
		readErr     error
 | 
			
		||||
		elems       = make([]*QueueOutboundElement, batchSize)
 | 
			
		||||
		buffs       = make([][]byte, batchSize)
 | 
			
		||||
		bufs        = make([][]byte, batchSize)
 | 
			
		||||
		elemsByPeer = make(map[*Peer]*[]*QueueOutboundElement, batchSize)
 | 
			
		||||
		count       = 0
 | 
			
		||||
		sizes       = make([]int, batchSize)
 | 
			
		||||
@ -226,7 +226,7 @@ func (device *Device) RoutineReadFromTUN() {
 | 
			
		||||
 | 
			
		||||
	for i := range elems {
 | 
			
		||||
		elems[i] = device.NewOutboundElement()
 | 
			
		||||
		buffs[i] = elems[i].buffer[:]
 | 
			
		||||
		bufs[i] = elems[i].buffer[:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
@ -240,14 +240,14 @@ func (device *Device) RoutineReadFromTUN() {
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		// read packets
 | 
			
		||||
		count, readErr = device.tun.device.Read(buffs, sizes, offset)
 | 
			
		||||
		count, readErr = device.tun.device.Read(bufs, sizes, offset)
 | 
			
		||||
		for i := 0; i < count; i++ {
 | 
			
		||||
			if sizes[i] < 1 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			elem := elems[i]
 | 
			
		||||
			elem.packet = buffs[i][offset : offset+sizes[i]]
 | 
			
		||||
			elem.packet = bufs[i][offset : offset+sizes[i]]
 | 
			
		||||
 | 
			
		||||
			// lookup peer
 | 
			
		||||
			var peer *Peer
 | 
			
		||||
@ -280,7 +280,7 @@ func (device *Device) RoutineReadFromTUN() {
 | 
			
		||||
			}
 | 
			
		||||
			*elemsForPeer = append(*elemsForPeer, elem)
 | 
			
		||||
			elems[i] = device.NewOutboundElement()
 | 
			
		||||
			buffs[i] = elems[i].buffer[:]
 | 
			
		||||
			bufs[i] = elems[i].buffer[:]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for peer, elemsForPeer := range elemsByPeer {
 | 
			
		||||
@ -483,10 +483,10 @@ func (peer *Peer) RoutineSequentialSender(maxBatchSize int) {
 | 
			
		||||
	}()
 | 
			
		||||
	device.log.Verbosef("%v - Routine: sequential sender - started", peer)
 | 
			
		||||
 | 
			
		||||
	buffs := make([][]byte, 0, maxBatchSize)
 | 
			
		||||
	bufs := make([][]byte, 0, maxBatchSize)
 | 
			
		||||
 | 
			
		||||
	for elems := range peer.queue.outbound.c {
 | 
			
		||||
		buffs = buffs[:0]
 | 
			
		||||
		bufs = bufs[:0]
 | 
			
		||||
		if elems == nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
@ -510,13 +510,13 @@ func (peer *Peer) RoutineSequentialSender(maxBatchSize int) {
 | 
			
		||||
			if len(elem.packet) != MessageKeepaliveSize {
 | 
			
		||||
				dataSent = true
 | 
			
		||||
			}
 | 
			
		||||
			buffs = append(buffs, elem.packet)
 | 
			
		||||
			bufs = append(bufs, elem.packet)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		peer.timersAnyAuthenticatedPacketTraversal()
 | 
			
		||||
		peer.timersAnyAuthenticatedPacketSent()
 | 
			
		||||
 | 
			
		||||
		err := peer.SendBuffers(buffs)
 | 
			
		||||
		err := peer.SendBuffers(bufs)
 | 
			
		||||
		if dataSent {
 | 
			
		||||
			peer.timersDataSent()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -96,7 +96,7 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func(l *UAPIListener) {
 | 
			
		||||
		var buff [0]byte
 | 
			
		||||
		var buf [0]byte
 | 
			
		||||
		for {
 | 
			
		||||
			defer uapi.inotifyRWCancel.Close()
 | 
			
		||||
			// start with lstat to avoid race condition
 | 
			
		||||
@ -104,7 +104,7 @@ func UAPIListen(name string, file *os.File) (net.Listener, error) {
 | 
			
		||||
				l.connErr <- err
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			_, err := uapi.inotifyRWCancel.Read(buff[:])
 | 
			
		||||
			_, err := uapi.inotifyRWCancel.Read(buf[:])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				l.connErr <- err
 | 
			
		||||
				return
 | 
			
		||||
 | 
			
		||||
@ -95,28 +95,28 @@ func newFlowKey(pkt []byte, srcAddr, dstAddr, tcphOffset int) flowKey {
 | 
			
		||||
// lookupOrInsert looks up a flow for the provided packet and metadata,
 | 
			
		||||
// returning the packets found for the flow, or inserting a new one if none
 | 
			
		||||
// is found.
 | 
			
		||||
func (t *tcpGROTable) lookupOrInsert(pkt []byte, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, buffsIndex int) ([]tcpGROItem, bool) {
 | 
			
		||||
func (t *tcpGROTable) lookupOrInsert(pkt []byte, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, bufsIndex int) ([]tcpGROItem, bool) {
 | 
			
		||||
	key := newFlowKey(pkt, srcAddrOffset, dstAddrOffset, tcphOffset)
 | 
			
		||||
	items, ok := t.itemsByFlow[key]
 | 
			
		||||
	if ok {
 | 
			
		||||
		return items, ok
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: insert() performs another map lookup. This could be rearranged to avoid.
 | 
			
		||||
	t.insert(pkt, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, buffsIndex)
 | 
			
		||||
	t.insert(pkt, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, bufsIndex)
 | 
			
		||||
	return nil, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// insert an item in the table for the provided packet and packet metadata.
 | 
			
		||||
func (t *tcpGROTable) insert(pkt []byte, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, buffsIndex int) {
 | 
			
		||||
func (t *tcpGROTable) insert(pkt []byte, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, bufsIndex int) {
 | 
			
		||||
	key := newFlowKey(pkt, srcAddrOffset, dstAddrOffset, tcphOffset)
 | 
			
		||||
	item := tcpGROItem{
 | 
			
		||||
		key:        key,
 | 
			
		||||
		buffsIndex: uint16(buffsIndex),
 | 
			
		||||
		gsoSize:    uint16(len(pkt[tcphOffset+tcphLen:])),
 | 
			
		||||
		iphLen:     uint8(tcphOffset),
 | 
			
		||||
		tcphLen:    uint8(tcphLen),
 | 
			
		||||
		sentSeq:    binary.BigEndian.Uint32(pkt[tcphOffset+4:]),
 | 
			
		||||
		pshSet:     pkt[tcphOffset+tcpFlagsOffset]&tcpFlagPSH != 0,
 | 
			
		||||
		key:       key,
 | 
			
		||||
		bufsIndex: uint16(bufsIndex),
 | 
			
		||||
		gsoSize:   uint16(len(pkt[tcphOffset+tcphLen:])),
 | 
			
		||||
		iphLen:    uint8(tcphOffset),
 | 
			
		||||
		tcphLen:   uint8(tcphLen),
 | 
			
		||||
		sentSeq:   binary.BigEndian.Uint32(pkt[tcphOffset+4:]),
 | 
			
		||||
		pshSet:    pkt[tcphOffset+tcpFlagsOffset]&tcpFlagPSH != 0,
 | 
			
		||||
	}
 | 
			
		||||
	items, ok := t.itemsByFlow[key]
 | 
			
		||||
	if !ok {
 | 
			
		||||
@ -140,14 +140,14 @@ func (t *tcpGROTable) deleteAt(key flowKey, i int) {
 | 
			
		||||
// tcpGROItem represents bookkeeping data for a TCP packet during the lifetime
 | 
			
		||||
// of a GRO evaluation across a vector of packets.
 | 
			
		||||
type tcpGROItem struct {
 | 
			
		||||
	key        flowKey
 | 
			
		||||
	sentSeq    uint32 // the sequence number
 | 
			
		||||
	buffsIndex uint16 // the index into the original buffs slice
 | 
			
		||||
	numMerged  uint16 // the number of packets merged into this item
 | 
			
		||||
	gsoSize    uint16 // payload size
 | 
			
		||||
	iphLen     uint8  // ip header len
 | 
			
		||||
	tcphLen    uint8  // tcp header len
 | 
			
		||||
	pshSet     bool   // psh flag is set
 | 
			
		||||
	key       flowKey
 | 
			
		||||
	sentSeq   uint32 // the sequence number
 | 
			
		||||
	bufsIndex uint16 // the index into the original bufs slice
 | 
			
		||||
	numMerged uint16 // the number of packets merged into this item
 | 
			
		||||
	gsoSize   uint16 // payload size
 | 
			
		||||
	iphLen    uint8  // ip header len
 | 
			
		||||
	tcphLen   uint8  // tcp header len
 | 
			
		||||
	pshSet    bool   // psh flag is set
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *tcpGROTable) newItems() []tcpGROItem {
 | 
			
		||||
@ -177,8 +177,8 @@ const (
 | 
			
		||||
// tcpPacketsCanCoalesce evaluates if pkt can be coalesced with the packet
 | 
			
		||||
// described by item. This function makes considerations that match the kernel's
 | 
			
		||||
// GRO self tests, which can be found in tools/testing/selftests/net/gro.c.
 | 
			
		||||
func tcpPacketsCanCoalesce(pkt []byte, iphLen, tcphLen uint8, seq uint32, pshSet bool, gsoSize uint16, item tcpGROItem, buffs [][]byte, buffsOffset int) canCoalesce {
 | 
			
		||||
	pktTarget := buffs[item.buffsIndex][buffsOffset:]
 | 
			
		||||
func tcpPacketsCanCoalesce(pkt []byte, iphLen, tcphLen uint8, seq uint32, pshSet bool, gsoSize uint16, item tcpGROItem, bufs [][]byte, bufsOffset int) canCoalesce {
 | 
			
		||||
	pktTarget := bufs[item.bufsIndex][bufsOffset:]
 | 
			
		||||
	if tcphLen != item.tcphLen {
 | 
			
		||||
		// cannot coalesce with unequal tcp options len
 | 
			
		||||
		return coalesceUnavailable
 | 
			
		||||
@ -262,18 +262,18 @@ const (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// coalesceTCPPackets attempts to coalesce pkt with the packet described by
 | 
			
		||||
// item, returning the outcome. This function may swap buffs elements in the
 | 
			
		||||
// event of a prepend as item's buffs index is already being tracked for writing
 | 
			
		||||
// item, returning the outcome. This function may swap bufs elements in the
 | 
			
		||||
// event of a prepend as item's bufs index is already being tracked for writing
 | 
			
		||||
// to a Device.
 | 
			
		||||
func coalesceTCPPackets(mode canCoalesce, pkt []byte, pktBuffsIndex int, gsoSize uint16, seq uint32, pshSet bool, item *tcpGROItem, buffs [][]byte, buffsOffset int, isV6 bool) coalesceResult {
 | 
			
		||||
func coalesceTCPPackets(mode canCoalesce, pkt []byte, pktBuffsIndex int, gsoSize uint16, seq uint32, pshSet bool, item *tcpGROItem, bufs [][]byte, bufsOffset int, isV6 bool) coalesceResult {
 | 
			
		||||
	var pktHead []byte // the packet that will end up at the front
 | 
			
		||||
	headersLen := item.iphLen + item.tcphLen
 | 
			
		||||
	coalescedLen := len(buffs[item.buffsIndex][buffsOffset:]) + len(pkt) - int(headersLen)
 | 
			
		||||
	coalescedLen := len(bufs[item.bufsIndex][bufsOffset:]) + len(pkt) - int(headersLen)
 | 
			
		||||
 | 
			
		||||
	// Copy data
 | 
			
		||||
	if mode == coalescePrepend {
 | 
			
		||||
		pktHead = pkt
 | 
			
		||||
		if cap(pkt)-buffsOffset < coalescedLen {
 | 
			
		||||
		if cap(pkt)-bufsOffset < coalescedLen {
 | 
			
		||||
			// We don't want to allocate a new underlying array if capacity is
 | 
			
		||||
			// too small.
 | 
			
		||||
			return coalesceInsufficientCap
 | 
			
		||||
@ -282,7 +282,7 @@ func coalesceTCPPackets(mode canCoalesce, pkt []byte, pktBuffsIndex int, gsoSize
 | 
			
		||||
			return coalescePSHEnding
 | 
			
		||||
		}
 | 
			
		||||
		if item.numMerged == 0 {
 | 
			
		||||
			if !tcpChecksumValid(buffs[item.buffsIndex][buffsOffset:], item.iphLen, isV6) {
 | 
			
		||||
			if !tcpChecksumValid(bufs[item.bufsIndex][bufsOffset:], item.iphLen, isV6) {
 | 
			
		||||
				return coalesceItemInvalidCSum
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -291,20 +291,20 @@ func coalesceTCPPackets(mode canCoalesce, pkt []byte, pktBuffsIndex int, gsoSize
 | 
			
		||||
		}
 | 
			
		||||
		item.sentSeq = seq
 | 
			
		||||
		extendBy := coalescedLen - len(pktHead)
 | 
			
		||||
		buffs[pktBuffsIndex] = append(buffs[pktBuffsIndex], make([]byte, extendBy)...)
 | 
			
		||||
		copy(buffs[pktBuffsIndex][buffsOffset+len(pkt):], buffs[item.buffsIndex][buffsOffset+int(headersLen):])
 | 
			
		||||
		// Flip the slice headers in buffs as part of prepend. The index of item
 | 
			
		||||
		bufs[pktBuffsIndex] = append(bufs[pktBuffsIndex], make([]byte, extendBy)...)
 | 
			
		||||
		copy(bufs[pktBuffsIndex][bufsOffset+len(pkt):], bufs[item.bufsIndex][bufsOffset+int(headersLen):])
 | 
			
		||||
		// Flip the slice headers in bufs as part of prepend. The index of item
 | 
			
		||||
		// is already being tracked for writing.
 | 
			
		||||
		buffs[item.buffsIndex], buffs[pktBuffsIndex] = buffs[pktBuffsIndex], buffs[item.buffsIndex]
 | 
			
		||||
		bufs[item.bufsIndex], bufs[pktBuffsIndex] = bufs[pktBuffsIndex], bufs[item.bufsIndex]
 | 
			
		||||
	} else {
 | 
			
		||||
		pktHead = buffs[item.buffsIndex][buffsOffset:]
 | 
			
		||||
		if cap(pktHead)-buffsOffset < coalescedLen {
 | 
			
		||||
		pktHead = bufs[item.bufsIndex][bufsOffset:]
 | 
			
		||||
		if cap(pktHead)-bufsOffset < coalescedLen {
 | 
			
		||||
			// We don't want to allocate a new underlying array if capacity is
 | 
			
		||||
			// too small.
 | 
			
		||||
			return coalesceInsufficientCap
 | 
			
		||||
		}
 | 
			
		||||
		if item.numMerged == 0 {
 | 
			
		||||
			if !tcpChecksumValid(buffs[item.buffsIndex][buffsOffset:], item.iphLen, isV6) {
 | 
			
		||||
			if !tcpChecksumValid(bufs[item.bufsIndex][bufsOffset:], item.iphLen, isV6) {
 | 
			
		||||
				return coalesceItemInvalidCSum
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -317,8 +317,8 @@ func coalesceTCPPackets(mode canCoalesce, pkt []byte, pktBuffsIndex int, gsoSize
 | 
			
		||||
			pktHead[item.iphLen+tcpFlagsOffset] |= tcpFlagPSH
 | 
			
		||||
		}
 | 
			
		||||
		extendBy := len(pkt) - int(headersLen)
 | 
			
		||||
		buffs[item.buffsIndex] = append(buffs[item.buffsIndex], make([]byte, extendBy)...)
 | 
			
		||||
		copy(buffs[item.buffsIndex][buffsOffset+len(pktHead):], pkt[headersLen:])
 | 
			
		||||
		bufs[item.bufsIndex] = append(bufs[item.bufsIndex], make([]byte, extendBy)...)
 | 
			
		||||
		copy(bufs[item.bufsIndex][bufsOffset+len(pktHead):], pkt[headersLen:])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if gsoSize > item.gsoSize {
 | 
			
		||||
@ -344,7 +344,7 @@ func coalesceTCPPackets(mode canCoalesce, pkt []byte, pktBuffsIndex int, gsoSize
 | 
			
		||||
		iphCSum := ^checksum(pktHead[:item.iphLen], 0)                // compute checksum
 | 
			
		||||
		binary.BigEndian.PutUint16(pktHead[10:], iphCSum)             // set checksum field
 | 
			
		||||
	}
 | 
			
		||||
	hdr.encode(buffs[item.buffsIndex][buffsOffset-virtioNetHdrLen:])
 | 
			
		||||
	hdr.encode(bufs[item.bufsIndex][bufsOffset-virtioNetHdrLen:])
 | 
			
		||||
 | 
			
		||||
	// Calculate the pseudo header checksum and place it at the TCP checksum
 | 
			
		||||
	// offset. Downstream checksum offloading will combine this with computation
 | 
			
		||||
@ -355,9 +355,9 @@ func coalesceTCPPackets(mode canCoalesce, pkt []byte, pktBuffsIndex int, gsoSize
 | 
			
		||||
		addrLen = 16
 | 
			
		||||
		addrOffset = ipv6SrcAddrOffset
 | 
			
		||||
	}
 | 
			
		||||
	srcAddrAt := buffsOffset + addrOffset
 | 
			
		||||
	srcAddr := buffs[item.buffsIndex][srcAddrAt : srcAddrAt+addrLen]
 | 
			
		||||
	dstAddr := buffs[item.buffsIndex][srcAddrAt+addrLen : srcAddrAt+addrLen*2]
 | 
			
		||||
	srcAddrAt := bufsOffset + addrOffset
 | 
			
		||||
	srcAddr := bufs[item.bufsIndex][srcAddrAt : srcAddrAt+addrLen]
 | 
			
		||||
	dstAddr := bufs[item.bufsIndex][srcAddrAt+addrLen : srcAddrAt+addrLen*2]
 | 
			
		||||
	psum := pseudoHeaderChecksumNoFold(unix.IPPROTO_TCP, srcAddr, dstAddr, uint16(coalescedLen-int(item.iphLen)))
 | 
			
		||||
	binary.BigEndian.PutUint16(pktHead[hdr.csumStart+hdr.csumOffset:], checksum([]byte{}, psum))
 | 
			
		||||
 | 
			
		||||
@ -375,12 +375,12 @@ const (
 | 
			
		||||
	maxUint16         = 1<<16 - 1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// tcpGRO evaluates the TCP packet at pktI in buffs for coalescing with
 | 
			
		||||
// tcpGRO evaluates the TCP packet at pktI in bufs for coalescing with
 | 
			
		||||
// existing packets tracked in table. It will return false when pktI is not
 | 
			
		||||
// coalesced, otherwise true. This indicates to the caller if buffs[pktI]
 | 
			
		||||
// coalesced, otherwise true. This indicates to the caller if bufs[pktI]
 | 
			
		||||
// should be written to the Device.
 | 
			
		||||
func tcpGRO(buffs [][]byte, offset int, pktI int, table *tcpGROTable, isV6 bool) (pktCoalesced bool) {
 | 
			
		||||
	pkt := buffs[pktI][offset:]
 | 
			
		||||
func tcpGRO(bufs [][]byte, offset int, pktI int, table *tcpGROTable, isV6 bool) (pktCoalesced bool) {
 | 
			
		||||
	pkt := bufs[pktI][offset:]
 | 
			
		||||
	if len(pkt) > maxUint16 {
 | 
			
		||||
		// A valid IPv4 or IPv6 packet will never exceed this.
 | 
			
		||||
		return false
 | 
			
		||||
@ -452,9 +452,9 @@ func tcpGRO(buffs [][]byte, offset int, pktI int, table *tcpGROTable, isV6 bool)
 | 
			
		||||
		// sequence number perspective, however once an item is inserted into
 | 
			
		||||
		// the table it is never compared across other items later.
 | 
			
		||||
		item := items[i]
 | 
			
		||||
		can := tcpPacketsCanCoalesce(pkt, uint8(iphLen), uint8(tcphLen), seq, pshSet, gsoSize, item, buffs, offset)
 | 
			
		||||
		can := tcpPacketsCanCoalesce(pkt, uint8(iphLen), uint8(tcphLen), seq, pshSet, gsoSize, item, bufs, offset)
 | 
			
		||||
		if can != coalesceUnavailable {
 | 
			
		||||
			result := coalesceTCPPackets(can, pkt, pktI, gsoSize, seq, pshSet, &item, buffs, offset, isV6)
 | 
			
		||||
			result := coalesceTCPPackets(can, pkt, pktI, gsoSize, seq, pshSet, &item, bufs, offset, isV6)
 | 
			
		||||
			switch result {
 | 
			
		||||
			case coalesceSuccess:
 | 
			
		||||
				table.updateAt(item, i)
 | 
			
		||||
@ -500,25 +500,25 @@ func isTCP6NoEH(b []byte) bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// handleGRO evaluates buffs for GRO, and writes the indices of the resulting
 | 
			
		||||
// handleGRO evaluates bufs for GRO, and writes the indices of the resulting
 | 
			
		||||
// packets into toWrite. toWrite, tcp4Table, and tcp6Table should initially be
 | 
			
		||||
// empty (but non-nil), and are passed in to save allocs as the caller may reset
 | 
			
		||||
// and recycle them across vectors of packets.
 | 
			
		||||
func handleGRO(buffs [][]byte, offset int, tcp4Table, tcp6Table *tcpGROTable, toWrite *[]int) error {
 | 
			
		||||
	for i := range buffs {
 | 
			
		||||
		if offset < virtioNetHdrLen || offset > len(buffs[i])-1 {
 | 
			
		||||
func handleGRO(bufs [][]byte, offset int, tcp4Table, tcp6Table *tcpGROTable, toWrite *[]int) error {
 | 
			
		||||
	for i := range bufs {
 | 
			
		||||
		if offset < virtioNetHdrLen || offset > len(bufs[i])-1 {
 | 
			
		||||
			return errors.New("invalid offset")
 | 
			
		||||
		}
 | 
			
		||||
		var coalesced bool
 | 
			
		||||
		switch {
 | 
			
		||||
		case isTCP4(buffs[i][offset:]):
 | 
			
		||||
			coalesced = tcpGRO(buffs, offset, i, tcp4Table, false)
 | 
			
		||||
		case isTCP6NoEH(buffs[i][offset:]): // ipv6 packets w/extension headers do not coalesce
 | 
			
		||||
			coalesced = tcpGRO(buffs, offset, i, tcp6Table, true)
 | 
			
		||||
		case isTCP4(bufs[i][offset:]):
 | 
			
		||||
			coalesced = tcpGRO(bufs, offset, i, tcp4Table, false)
 | 
			
		||||
		case isTCP6NoEH(bufs[i][offset:]): // ipv6 packets w/extension headers do not coalesce
 | 
			
		||||
			coalesced = tcpGRO(bufs, offset, i, tcp6Table, true)
 | 
			
		||||
		}
 | 
			
		||||
		if !coalesced {
 | 
			
		||||
			hdr := virtioNetHdr{}
 | 
			
		||||
			err := hdr.encode(buffs[i][offset-virtioNetHdrLen:])
 | 
			
		||||
			err := hdr.encode(bufs[i][offset-virtioNetHdrLen:])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								tun/tun.go
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								tun/tun.go
									
									
									
									
									
								
							@ -23,16 +23,16 @@ type Device interface {
 | 
			
		||||
 | 
			
		||||
	// Read one or more packets from the Device (without any additional headers).
 | 
			
		||||
	// On a successful read it returns the number of packets read, and sets
 | 
			
		||||
	// packet lengths within the sizes slice. len(sizes) must be >= len(buffs).
 | 
			
		||||
	// packet lengths within the sizes slice. len(sizes) must be >= len(bufs).
 | 
			
		||||
	// A nonzero offset can be used to instruct the Device on where to begin
 | 
			
		||||
	// reading into each element of the buffs slice.
 | 
			
		||||
	Read(buffs [][]byte, sizes []int, offset int) (n int, err error)
 | 
			
		||||
	// reading into each element of the bufs slice.
 | 
			
		||||
	Read(bufs [][]byte, sizes []int, offset int) (n int, err error)
 | 
			
		||||
 | 
			
		||||
	// Write one or more packets to the device (without any additional headers).
 | 
			
		||||
	// On a successful write it returns the number of packets written. A nonzero
 | 
			
		||||
	// offset can be used to instruct the Device on where to begin writing from
 | 
			
		||||
	// each packet contained within the buffs slice.
 | 
			
		||||
	Write(buffs [][]byte, offset int) (int, error)
 | 
			
		||||
	// each packet contained within the bufs slice.
 | 
			
		||||
	Write(bufs [][]byte, offset int) (int, error)
 | 
			
		||||
 | 
			
		||||
	// MTU returns the MTU of the Device.
 | 
			
		||||
	MTU() (int, error)
 | 
			
		||||
 | 
			
		||||
@ -217,7 +217,7 @@ func (tun *NativeTun) Events() <-chan Event {
 | 
			
		||||
	return tun.events
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
	// TODO: the BSDs look very similar in Read() and Write(). They should be
 | 
			
		||||
	// collapsed, with platform-specific files containing the varying parts of
 | 
			
		||||
	// their implementations.
 | 
			
		||||
@ -225,8 +225,8 @@ func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error)
 | 
			
		||||
	case err := <-tun.errors:
 | 
			
		||||
		return 0, err
 | 
			
		||||
	default:
 | 
			
		||||
		buff := buffs[0][offset-4:]
 | 
			
		||||
		n, err := tun.tunFile.Read(buff[:])
 | 
			
		||||
		buf := bufs[0][offset-4:]
 | 
			
		||||
		n, err := tun.tunFile.Read(buf[:])
 | 
			
		||||
		if n < 4 {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
@ -235,11 +235,11 @@ func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) {
 | 
			
		||||
	if offset < 4 {
 | 
			
		||||
		return 0, io.ErrShortBuffer
 | 
			
		||||
	}
 | 
			
		||||
	for i, buf := range buffs {
 | 
			
		||||
	for i, buf := range bufs {
 | 
			
		||||
		buf = buf[offset-4:]
 | 
			
		||||
		buf[0] = 0x00
 | 
			
		||||
		buf[1] = 0x00
 | 
			
		||||
@ -256,7 +256,7 @@ func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
			return i, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return len(buffs), nil
 | 
			
		||||
	return len(bufs), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Close() error {
 | 
			
		||||
 | 
			
		||||
@ -333,13 +333,13 @@ func (tun *NativeTun) Events() <-chan Event {
 | 
			
		||||
	return tun.events
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
	select {
 | 
			
		||||
	case err := <-tun.errors:
 | 
			
		||||
		return 0, err
 | 
			
		||||
	default:
 | 
			
		||||
		buff := buffs[0][offset-4:]
 | 
			
		||||
		n, err := tun.tunFile.Read(buff[:])
 | 
			
		||||
		buf := bufs[0][offset-4:]
 | 
			
		||||
		n, err := tun.tunFile.Read(buf[:])
 | 
			
		||||
		if n < 4 {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
@ -348,11 +348,11 @@ func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) {
 | 
			
		||||
	if offset < 4 {
 | 
			
		||||
		return 0, io.ErrShortBuffer
 | 
			
		||||
	}
 | 
			
		||||
	for i, buf := range buffs {
 | 
			
		||||
	for i, buf := range bufs {
 | 
			
		||||
		buf = buf[offset-4:]
 | 
			
		||||
		if len(buf) < 5 {
 | 
			
		||||
			return i, io.ErrShortBuffer
 | 
			
		||||
@ -372,7 +372,7 @@ func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
			return i, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return len(buffs), nil
 | 
			
		||||
	return len(bufs), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Close() error {
 | 
			
		||||
 | 
			
		||||
@ -330,7 +330,7 @@ func (tun *NativeTun) nameSlow() (string, error) {
 | 
			
		||||
	return unix.ByteSliceToString(ifr[:]), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) {
 | 
			
		||||
	tun.writeOpMu.Lock()
 | 
			
		||||
	defer func() {
 | 
			
		||||
		tun.tcp4GROTable.reset()
 | 
			
		||||
@ -343,18 +343,18 @@ func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
	)
 | 
			
		||||
	tun.toWrite = tun.toWrite[:0]
 | 
			
		||||
	if tun.vnetHdr {
 | 
			
		||||
		err := handleGRO(buffs, offset, tun.tcp4GROTable, tun.tcp6GROTable, &tun.toWrite)
 | 
			
		||||
		err := handleGRO(bufs, offset, tun.tcp4GROTable, tun.tcp6GROTable, &tun.toWrite)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		offset -= virtioNetHdrLen
 | 
			
		||||
	} else {
 | 
			
		||||
		for i := range buffs {
 | 
			
		||||
		for i := range bufs {
 | 
			
		||||
			tun.toWrite = append(tun.toWrite, i)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, buffsI := range tun.toWrite {
 | 
			
		||||
		n, err := tun.tunFile.Write(buffs[buffsI][offset:])
 | 
			
		||||
	for _, bufsI := range tun.toWrite {
 | 
			
		||||
		n, err := tun.tunFile.Write(bufs[bufsI][offset:])
 | 
			
		||||
		if errors.Is(err, syscall.EBADFD) {
 | 
			
		||||
			return total, os.ErrClosed
 | 
			
		||||
		}
 | 
			
		||||
@ -367,10 +367,10 @@ func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
	return total, ErrorBatch(errs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// handleVirtioRead splits in into buffs, leaving offset bytes at the front of
 | 
			
		||||
// each buffer. It mutates sizes to reflect the size of each element of buffs,
 | 
			
		||||
// handleVirtioRead splits in into bufs, leaving offset bytes at the front of
 | 
			
		||||
// each buffer. It mutates sizes to reflect the size of each element of bufs,
 | 
			
		||||
// and returns the number of packets read.
 | 
			
		||||
func handleVirtioRead(in []byte, buffs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
func handleVirtioRead(in []byte, bufs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
	var hdr virtioNetHdr
 | 
			
		||||
	err := hdr.decode(in)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@ -387,10 +387,10 @@ func handleVirtioRead(in []byte, buffs [][]byte, sizes []int, offset int) (int,
 | 
			
		||||
				return 0, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if len(in) > len(buffs[0][offset:]) {
 | 
			
		||||
			return 0, fmt.Errorf("read len %d overflows buffs element len %d", len(in), len(buffs[0][offset:]))
 | 
			
		||||
		if len(in) > len(bufs[0][offset:]) {
 | 
			
		||||
			return 0, fmt.Errorf("read len %d overflows bufs element len %d", len(in), len(bufs[0][offset:]))
 | 
			
		||||
		}
 | 
			
		||||
		n := copy(buffs[0][offset:], in)
 | 
			
		||||
		n := copy(bufs[0][offset:], in)
 | 
			
		||||
		sizes[0] = n
 | 
			
		||||
		return 1, nil
 | 
			
		||||
	}
 | 
			
		||||
@ -438,17 +438,17 @@ func handleVirtioRead(in []byte, buffs [][]byte, sizes []int, offset int) (int,
 | 
			
		||||
		return 0, fmt.Errorf("end of checksum offset (%d) exceeds packet length (%d)", cSumAt+1, len(in))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tcpTSO(in, hdr, buffs, sizes, offset)
 | 
			
		||||
	return tcpTSO(in, hdr, bufs, sizes, offset)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
	tun.readOpMu.Lock()
 | 
			
		||||
	defer tun.readOpMu.Unlock()
 | 
			
		||||
	select {
 | 
			
		||||
	case err := <-tun.errors:
 | 
			
		||||
		return 0, err
 | 
			
		||||
	default:
 | 
			
		||||
		readInto := buffs[0][offset:]
 | 
			
		||||
		readInto := bufs[0][offset:]
 | 
			
		||||
		if tun.vnetHdr {
 | 
			
		||||
			readInto = tun.readBuff[:]
 | 
			
		||||
		}
 | 
			
		||||
@ -460,7 +460,7 @@ func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error)
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		if tun.vnetHdr {
 | 
			
		||||
			return handleVirtioRead(readInto[:n], buffs, sizes, offset)
 | 
			
		||||
			return handleVirtioRead(readInto[:n], bufs, sizes, offset)
 | 
			
		||||
		} else {
 | 
			
		||||
			sizes[0] = n
 | 
			
		||||
			return 1, nil
 | 
			
		||||
 | 
			
		||||
@ -204,13 +204,13 @@ func (tun *NativeTun) Events() <-chan Event {
 | 
			
		||||
	return tun.events
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
	select {
 | 
			
		||||
	case err := <-tun.errors:
 | 
			
		||||
		return 0, err
 | 
			
		||||
	default:
 | 
			
		||||
		buff := buffs[0][offset-4:]
 | 
			
		||||
		n, err := tun.tunFile.Read(buff[:])
 | 
			
		||||
		buf := bufs[0][offset-4:]
 | 
			
		||||
		n, err := tun.tunFile.Read(buf[:])
 | 
			
		||||
		if n < 4 {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
@ -219,11 +219,11 @@ func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) {
 | 
			
		||||
	if offset < 4 {
 | 
			
		||||
		return 0, io.ErrShortBuffer
 | 
			
		||||
	}
 | 
			
		||||
	for i, buf := range buffs {
 | 
			
		||||
	for i, buf := range bufs {
 | 
			
		||||
		buf = buf[offset-4:]
 | 
			
		||||
		buf[0] = 0x00
 | 
			
		||||
		buf[1] = 0x00
 | 
			
		||||
@ -240,7 +240,7 @@ func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
			return i, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return len(buffs), nil
 | 
			
		||||
	return len(bufs), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Close() error {
 | 
			
		||||
 | 
			
		||||
@ -141,7 +141,7 @@ func (tun *NativeTun) BatchSize() int {
 | 
			
		||||
 | 
			
		||||
// Note: Read() and Write() assume the caller comes only from a single thread; there's no locking.
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) {
 | 
			
		||||
	tun.running.Add(1)
 | 
			
		||||
	defer tun.running.Done()
 | 
			
		||||
retry:
 | 
			
		||||
@ -158,7 +158,7 @@ retry:
 | 
			
		||||
		switch err {
 | 
			
		||||
		case nil:
 | 
			
		||||
			packetSize := len(packet)
 | 
			
		||||
			copy(buffs[0][offset:], packet)
 | 
			
		||||
			copy(bufs[0][offset:], packet)
 | 
			
		||||
			sizes[0] = packetSize
 | 
			
		||||
			tun.session.ReleaseReceivePacket(packet)
 | 
			
		||||
			tun.rate.update(uint64(packetSize))
 | 
			
		||||
@ -179,22 +179,22 @@ retry:
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) {
 | 
			
		||||
	tun.running.Add(1)
 | 
			
		||||
	defer tun.running.Done()
 | 
			
		||||
	if tun.close.Load() {
 | 
			
		||||
		return 0, os.ErrClosed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, buff := range buffs {
 | 
			
		||||
		packetSize := len(buff) - offset
 | 
			
		||||
	for i, buf := range bufs {
 | 
			
		||||
		packetSize := len(buf) - offset
 | 
			
		||||
		tun.rate.update(uint64(packetSize))
 | 
			
		||||
 | 
			
		||||
		packet, err := tun.session.AllocateSendPacket(packetSize)
 | 
			
		||||
		switch err {
 | 
			
		||||
		case nil:
 | 
			
		||||
			// TODO: Explore options to eliminate this copy.
 | 
			
		||||
			copy(packet, buff[offset:])
 | 
			
		||||
			copy(packet, buf[offset:])
 | 
			
		||||
			tun.session.SendPacket(packet)
 | 
			
		||||
			continue
 | 
			
		||||
		case windows.ERROR_HANDLE_EOF:
 | 
			
		||||
@ -205,7 +205,7 @@ func (tun *NativeTun) Write(buffs [][]byte, offset int) (int, error) {
 | 
			
		||||
			return i, fmt.Errorf("Write failed: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return len(buffs), nil
 | 
			
		||||
	return len(bufs), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LUID returns Windows interface instance ID.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user