]> Cypherpunks repositories - gostls13.git/commitdiff
net: permit WriteMsgUDP to connected UDP sockets
authorNicolas S. Dade <nic.dade@gmail.com>
Thu, 5 Feb 2015 02:05:53 +0000 (18:05 -0800)
committerMikio Hara <mikioh.mikioh@gmail.com>
Tue, 10 Feb 2015 08:00:39 +0000 (08:00 +0000)
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 <mikioh.mikioh@gmail.com>
src/net/udp_test.go
src/net/udpsock_posix.go

index 125bbca6c40e9405b5691cb8addacf705894c361..d291b26fd5bf8fce58bb1491f6881b2b7e4772d3 100644 (file)
@@ -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 {
index a0533366a42fd5fd1f68312070138c47fc69e91f..0770b7c5cee589d2582a9bef29420ac45b3f448a 100644 (file)
@@ -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)