uquic/send_conn_test.go
Gaukas Wang 4973374ea5
sync: quic-go 0.42.0
Signed-off-by: Gaukas Wang <i@gaukas.wang>
2024-04-23 22:34:55 -06:00

102 lines
4.3 KiB
Go

package quic
import (
"net"
"net/netip"
"runtime"
"github.com/refraction-networking/uquic/internal/protocol"
"github.com/refraction-networking/uquic/internal/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"go.uber.org/mock/gomock"
)
// Only if appendUDPSegmentSizeMsg actually appends a message (and isn't only a stub implementation),
// GSO is actually supported on this platform.
var platformSupportsGSO = len(appendUDPSegmentSizeMsg([]byte{}, 1337)) > 0
var _ = Describe("Connection (for sending packets)", func() {
remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337}
It("gets the local and remote addresses", func() {
localAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1234}
rawConn := NewMockRawConn(mockCtrl)
rawConn.EXPECT().LocalAddr().Return(localAddr)
c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger)
Expect(c.LocalAddr().String()).To(Equal("192.168.0.1:1234"))
Expect(c.RemoteAddr().String()).To(Equal("192.168.100.200:1337"))
})
It("uses the local address from the packet info", func() {
localAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1234}
rawConn := NewMockRawConn(mockCtrl)
rawConn.EXPECT().LocalAddr().Return(localAddr)
c := newSendConn(rawConn, remoteAddr, packetInfo{addr: netip.AddrFrom4([4]byte{127, 0, 0, 42})}, utils.DefaultLogger)
Expect(c.LocalAddr().String()).To(Equal("127.0.0.42:1234"))
})
// We're not using an OOB conn on windows, and packetInfo.OOB() always returns an empty slice.
if runtime.GOOS != "windows" {
It("sets the OOB", func() {
rawConn := NewMockRawConn(mockCtrl)
rawConn.EXPECT().LocalAddr()
rawConn.EXPECT().capabilities().AnyTimes()
pi := packetInfo{addr: netip.IPv6Loopback()}
Expect(pi.OOB()).ToNot(BeEmpty())
c := newSendConn(rawConn, remoteAddr, pi, utils.DefaultLogger)
rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, pi.OOB(), uint16(0), protocol.ECT1)
Expect(c.Write([]byte("foobar"), 0, protocol.ECT1)).To(Succeed())
})
}
It("writes", func() {
rawConn := NewMockRawConn(mockCtrl)
rawConn.EXPECT().LocalAddr()
rawConn.EXPECT().capabilities().AnyTimes()
c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger)
rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, gomock.Any(), uint16(3), protocol.ECNCE)
Expect(c.Write([]byte("foobar"), 3, protocol.ECNCE)).To(Succeed())
})
if platformSupportsGSO {
It("disables GSO if sending fails", func() {
rawConn := NewMockRawConn(mockCtrl)
rawConn.EXPECT().LocalAddr()
rawConn.EXPECT().capabilities().Return(connCapabilities{GSO: true}).AnyTimes()
c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger)
Expect(c.capabilities().GSO).To(BeTrue())
gomock.InOrder(
rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, gomock.Any(), uint16(4), protocol.ECNCE).Return(0, errGSO),
rawConn.EXPECT().WritePacket([]byte("foob"), remoteAddr, gomock.Any(), uint16(0), protocol.ECNCE).Return(4, nil),
rawConn.EXPECT().WritePacket([]byte("ar"), remoteAddr, gomock.Any(), uint16(0), protocol.ECNCE).Return(2, nil),
)
Expect(c.Write([]byte("foobar"), 4, protocol.ECNCE)).To(Succeed())
Expect(c.capabilities().GSO).To(BeFalse())
})
}
if runtime.GOOS == "linux" {
It("doesn't fail if the very first sendmsg call fails", func() {
rawConn := NewMockRawConn(mockCtrl)
rawConn.EXPECT().LocalAddr()
rawConn.EXPECT().capabilities().AnyTimes()
c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger)
gomock.InOrder(
rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, gomock.Any(), gomock.Any(), protocol.ECNCE).Return(0, errNotPermitted),
rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, gomock.Any(), uint16(0), protocol.ECNCE).Return(6, nil),
)
Expect(c.Write([]byte("foobar"), 0, protocol.ECNCE)).To(Succeed())
})
It("fails if the sendmsg calls fail multiple times", func() {
rawConn := NewMockRawConn(mockCtrl)
rawConn.EXPECT().LocalAddr()
rawConn.EXPECT().capabilities().AnyTimes()
c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger)
rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, gomock.Any(), gomock.Any(), protocol.ECNCE).Return(0, errNotPermitted).Times(2)
Expect(c.Write([]byte("foobar"), 0, protocol.ECNCE)).To(MatchError(errNotPermitted))
})
}
})