Skip to content

Commit 376ba58

Browse files
author
Lars Gierth
authored
Merge pull request #31 from multiformats/feat/udp
Added UDP datagram packet connection support.
2 parents f41dec4 + 49f84c7 commit 376ba58

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

net.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,81 @@ func WrapNetListener(nl net.Listener) (Listener, error) {
248248
}, nil
249249
}
250250

251+
// A PacketConn is a generic packet oriented network connection which uses an
252+
// underlying net.PacketConn, wrapped with the locally bound Multiaddr.
253+
type PacketConn interface {
254+
Connection() net.PacketConn
255+
256+
Multiaddr() ma.Multiaddr
257+
258+
ReadFrom(b []byte) (int, ma.Multiaddr, error)
259+
WriteTo(b []byte, maddr ma.Multiaddr) (int, error)
260+
261+
Close() error
262+
}
263+
264+
// maPacketConn implements PacketConn
265+
type maPacketConn struct {
266+
net.PacketConn
267+
laddr ma.Multiaddr
268+
}
269+
270+
// Connection returns the embedded net.PacketConn.
271+
func (l *maPacketConn) Connection() net.PacketConn {
272+
return l.PacketConn
273+
}
274+
275+
// Multiaddr returns the bound local Multiaddr.
276+
func (l *maPacketConn) Multiaddr() ma.Multiaddr {
277+
return l.laddr
278+
}
279+
280+
func (l *maPacketConn) ReadFrom(b []byte) (int, ma.Multiaddr, error) {
281+
n, addr, err := l.PacketConn.ReadFrom(b)
282+
maddr, _ := FromNetAddr(addr)
283+
return n, maddr, err
284+
}
285+
286+
func (l *maPacketConn) WriteTo(b []byte, maddr ma.Multiaddr) (int, error) {
287+
addr, err := ToNetAddr(maddr)
288+
if err != nil {
289+
return 0, err
290+
}
291+
return l.PacketConn.WriteTo(b, addr)
292+
}
293+
294+
// ListenPacket announces on the local network address laddr.
295+
// The Multiaddr must be a packet driven network, like udp4 or udp6.
296+
// See Dial for the syntax of laddr.
297+
func ListenPacket(laddr ma.Multiaddr) (PacketConn, error) {
298+
lnet, lnaddr, err := DialArgs(laddr)
299+
if err != nil {
300+
return nil, err
301+
}
302+
303+
pc, err := net.ListenPacket(lnet, lnaddr)
304+
if err != nil {
305+
return nil, err
306+
}
307+
308+
// We want to fetch the new multiaddr from the listener, as it may
309+
// have resolved to some other value. WrapPacketConn does this.
310+
return WrapPacketConn(pc)
311+
}
312+
313+
// WrapPacketConn wraps a net.PacketConn with a manet.PacketConn.
314+
func WrapPacketConn(pc net.PacketConn) (PacketConn, error) {
315+
laddr, err := FromNetAddr(pc.LocalAddr())
316+
if err != nil {
317+
return nil, err
318+
}
319+
320+
return &maPacketConn{
321+
PacketConn: pc,
322+
laddr: laddr,
323+
}, nil
324+
}
325+
251326
// InterfaceMultiaddrs will return the addresses matching net.InterfaceAddrs
252327
func InterfaceMultiaddrs() ([]ma.Multiaddr, error) {
253328
addrs, err := net.InterfaceAddrs()

net_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,59 @@ func TestListenAndDial(t *testing.T) {
244244
wg.Wait()
245245
}
246246

247+
func TestListenPacketAndDial(t *testing.T) {
248+
maddr := newMultiaddr(t, "/ip4/127.0.0.1/udp/4324")
249+
pc, err := ListenPacket(maddr)
250+
if err != nil {
251+
t.Fatal("failed to listen", err)
252+
}
253+
254+
var wg sync.WaitGroup
255+
wg.Add(1)
256+
257+
go func() {
258+
if !pc.Multiaddr().Equal(maddr) {
259+
t.Fatal("connection multiaddr not equal:", maddr, pc.Multiaddr())
260+
}
261+
262+
buffer := make([]byte, 1024)
263+
_, addr, err := pc.ReadFrom(buffer)
264+
if err != nil {
265+
t.Fatal("failed to read into buffer", err)
266+
}
267+
pc.WriteTo(buffer, addr)
268+
269+
wg.Done()
270+
}()
271+
272+
cn, err := Dial(maddr)
273+
if err != nil {
274+
t.Fatal("failed to dial", err)
275+
}
276+
277+
buf := make([]byte, 1024)
278+
if _, err := cn.Write([]byte("beep boop")); err != nil {
279+
t.Fatal("failed to write", err)
280+
}
281+
282+
if _, err := cn.Read(buf); err != nil {
283+
t.Fatal("failed to read:", buf, err)
284+
}
285+
286+
if !bytes.Equal(buf[:9], []byte("beep boop")) {
287+
t.Fatal("failed to echk:", buf)
288+
}
289+
290+
maddr2 := cn.RemoteMultiaddr()
291+
if !maddr2.Equal(maddr) {
292+
t.Fatal("remote multiaddr not equal:", maddr, maddr2)
293+
}
294+
295+
cn.Close()
296+
pc.Close()
297+
wg.Wait()
298+
}
299+
247300
func TestIPLoopback(t *testing.T) {
248301
if IP4Loopback.String() != "/ip4/127.0.0.1" {
249302
t.Error("IP4Loopback incorrect:", IP4Loopback)

0 commit comments

Comments
 (0)