From 263405ea4ac29e2c70e6e0bd3793e54c60f3a305 Mon Sep 17 00:00:00 2001 From: "Nicolas S. Dade" Date: Wed, 4 Feb 2015 18:05:53 -0800 Subject: [PATCH] net: permit WriteMsgUDP to connected UDP sockets The sanity checks at the beginning of WriteMsgUDP were too strict, and did not allow a case sendmsg(2) suppports: sending to a connected UDP socket. This fixes the sanity checks. Either the socket is unconnected, and a destination addresses is required (what all existing callers must have been doing), or the socket is connected and an explicit destination address must not be used. Fixes #9807 Change-Id: I08d4ec3c2bf830335c402acfc0680c841cfcec71 Reviewed-on: https://go-review.googlesource.com/3951 Reviewed-by: Mikio Hara --- src/net/udp_test.go | 48 ++++++++++++++++++++++++++++++---------- src/net/udpsock_posix.go | 12 +++++----- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/net/udp_test.go b/src/net/udp_test.go index 125bbca6c4..d291b26fd5 100644 --- a/src/net/udp_test.go +++ b/src/net/udp_test.go @@ -81,26 +81,26 @@ func TestWriteToUDP(t *testing.T) { t.Skipf("skipping test on %q", runtime.GOOS) } - l, err := ListenPacket("udp", "127.0.0.1:0") + c, err := ListenPacket("udp", "127.0.0.1:0") if err != nil { - t.Fatalf("Listen failed: %v", err) + t.Fatal(err) } - defer l.Close() + defer c.Close() - testWriteToConn(t, l.LocalAddr().String()) - testWriteToPacketConn(t, l.LocalAddr().String()) + testWriteToConn(t, c.LocalAddr().String()) + testWriteToPacketConn(t, c.LocalAddr().String()) } func testWriteToConn(t *testing.T, raddr string) { c, err := Dial("udp", raddr) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } defer c.Close() ra, err := ResolveUDPAddr("udp", raddr) if err != nil { - t.Fatalf("ResolveUDPAddr failed: %v", err) + t.Fatal(err) } _, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra) @@ -121,36 +121,60 @@ func testWriteToConn(t *testing.T, raddr string) { _, err = c.Write([]byte("Connection-oriented mode socket")) if err != nil { - t.Fatalf("Write failed: %v", err) + t.Fatal(err) + } + + _, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-oriented mode socket"), nil, ra) + if err == nil { + t.Fatal("WriteMsgUDP should fail") + } + if err != nil && err.(*OpError).Err != ErrWriteToConnected { + t.Fatalf("WriteMsgUDP should fail as ErrWriteToConnected: %v", err) + } + _, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-oriented mode socket"), nil, nil) + if err != nil { + t.Fatal(err) } } func testWriteToPacketConn(t *testing.T, raddr string) { c, err := ListenPacket("udp", "127.0.0.1:0") if err != nil { - t.Fatalf("ListenPacket failed: %v", err) + t.Fatal(err) } defer c.Close() ra, err := ResolveUDPAddr("udp", raddr) if err != nil { - t.Fatalf("ResolveUDPAddr failed: %v", err) + t.Fatal(err) } _, err = c.(*UDPConn).WriteToUDP([]byte("Connection-less mode socket"), ra) if err != nil { - t.Fatalf("WriteToUDP failed: %v", err) + t.Fatal(err) } _, err = c.WriteTo([]byte("Connection-less mode socket"), ra) if err != nil { - t.Fatalf("WriteTo failed: %v", err) + t.Fatal(err) } _, err = c.(*UDPConn).Write([]byte("Connection-less mode socket")) if err == nil { t.Fatal("Write should fail") } + + _, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-less mode socket"), nil, nil) + if err == nil { + t.Fatal("WriteMsgUDP should fail") + } + if err != nil && err.(*OpError).Err != errMissingAddress { + t.Fatalf("WriteMsgUDP should fail as errMissingAddress: %v", err) + } + _, _, err = c.(*UDPConn).WriteMsgUDP([]byte("Connection-less mode socket"), nil, ra) + if err != nil { + t.Fatal(err) + } } var udpConnLocalNameTests = []struct { diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go index a0533366a4..0770b7c5ce 100644 --- a/src/net/udpsock_posix.go +++ b/src/net/udpsock_posix.go @@ -139,17 +139,19 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) { return c.WriteToUDP(b, a) } -// WriteMsgUDP writes a packet to addr via c, copying the payload from -// b and the associated out-of-band data from oob. It returns the -// number of payload and out-of-band bytes written. +// WriteMsgUDP writes a packet to addr via c if c isn't connected, or +// to c's remote destination address if c is connected (in which case +// addr must be nil). The payload is copied from b and the associated +// out-of-band data is copied from oob. It returns the number of +// payload and out-of-band bytes written. func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { if !c.ok() { return 0, 0, syscall.EINVAL } - if c.fd.isConnected { + if c.fd.isConnected && addr != nil { return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected} } - if addr == nil { + if !c.fd.isConnected && addr == nil { return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} } sa, err := addr.sockaddr(c.fd.family)