Skip to content

Commit 5566b43

Browse files
neildgopherbot
authored andcommitted
quic: add the ability to create an endpoint with a fake network
Add a NewEndpoint function to create an *Endpoint using a net.PacketConn. We rely on a number of features of *net.UDPConn which aren't provided by PacketConn, so an Endpoint using anything other than a UDPConn will be limited. The main use case for providing a non-UDPConn connection is testing, in particular tests which use testing/synctest and cannot use a concrete network connection. Change-Id: I9e62cb8d7d545f64d99103beb9a32f149d4119bf Reviewed-on: https://go-review.googlesource.com/c/net/+/641498 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]> Auto-Submit: Damien Neil <[email protected]>
1 parent 97dd44e commit 5566b43

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

quic/endpoint.go

+19
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,25 @@ func Listen(network, address string, listenConfig *Config) (*Endpoint, error) {
7373
return newEndpoint(pc, listenConfig, nil)
7474
}
7575

76+
// NewEndpoint creates an endpoint using a net.PacketConn as the underlying transport.
77+
//
78+
// If the PacketConn is not a *net.UDPConn, the endpoint may be slower and lack
79+
// access to some features of the network.
80+
func NewEndpoint(conn net.PacketConn, config *Config) (*Endpoint, error) {
81+
var pc packetConn
82+
var err error
83+
switch conn := conn.(type) {
84+
case *net.UDPConn:
85+
pc, err = newNetUDPConn(conn)
86+
default:
87+
pc, err = newNetPacketConn(conn)
88+
}
89+
if err != nil {
90+
return nil, err
91+
}
92+
return newEndpoint(pc, config, nil)
93+
}
94+
7695
func newEndpoint(pc packetConn, config *Config, hooks endpointTestHooks) (*Endpoint, error) {
7796
e := &Endpoint{
7897
listenConfig: config,

quic/udp_packetconn.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build go1.21
6+
7+
package quic
8+
9+
import (
10+
"net"
11+
"net/netip"
12+
)
13+
14+
// netPacketConn is a packetConn implementation wrapping a net.PacketConn.
15+
//
16+
// This is mostly useful for tests, since PacketConn doesn't provide access to
17+
// important features such as identifying the local address packets were received on.
18+
type netPacketConn struct {
19+
c net.PacketConn
20+
localAddr netip.AddrPort
21+
}
22+
23+
func newNetPacketConn(pc net.PacketConn) (*netPacketConn, error) {
24+
addr, err := addrPortFromAddr(pc.LocalAddr())
25+
if err != nil {
26+
return nil, err
27+
}
28+
return &netPacketConn{
29+
c: pc,
30+
localAddr: addr,
31+
}, nil
32+
}
33+
34+
func (c *netPacketConn) Close() error {
35+
return c.c.Close()
36+
}
37+
38+
func (c *netPacketConn) LocalAddr() netip.AddrPort {
39+
return c.localAddr
40+
}
41+
42+
func (c *netPacketConn) Read(f func(*datagram)) {
43+
for {
44+
dgram := newDatagram()
45+
n, peerAddr, err := c.c.ReadFrom(dgram.b)
46+
if err != nil {
47+
return
48+
}
49+
dgram.peerAddr, err = addrPortFromAddr(peerAddr)
50+
if err != nil {
51+
continue
52+
}
53+
dgram.b = dgram.b[:n]
54+
f(dgram)
55+
}
56+
}
57+
58+
func (c *netPacketConn) Write(dgram datagram) error {
59+
_, err := c.c.WriteTo(dgram.b, net.UDPAddrFromAddrPort(dgram.peerAddr))
60+
return err
61+
}
62+
63+
func addrPortFromAddr(addr net.Addr) (netip.AddrPort, error) {
64+
switch a := addr.(type) {
65+
case *net.UDPAddr:
66+
return a.AddrPort(), nil
67+
}
68+
return netip.ParseAddrPort(addr.String())
69+
}

0 commit comments

Comments
 (0)