internal/socket: handle nil addr in sendMsgs
With the pool to reuse internal allocations for mmsghdrs introduced in
CL 315589, I've accidentally introduced a regression for sending
messages on dialed connections.
Calling sendMsgs with Messages with a nil address would panic during
(*msghdr).pack at msghdr_linux.go:18 when taking address of first
element of 0-sized buffer.
Handle this case by explicitly resetting the Name/Namelen.
Add test cases for writing to connected sockets.
Change-Id: I6d5dac696b7ab103a5290675c56002ede3e7b576
GitHub-Last-Rev: 4be010d03a0bcb86dda667952e3f60f096ebd3cc
GitHub-Pull-Request: golang/net#103
Reviewed-on: https://go-review.googlesource.com/c/net/+/316712
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Trust: Emmanuel Odeke <emmanuel@orijtech.com>
diff --git a/internal/socket/mmsghdr_unix.go b/internal/socket/mmsghdr_unix.go
index 42c4a0d..40ebeda 100644
--- a/internal/socket/mmsghdr_unix.go
+++ b/internal/socket/mmsghdr_unix.go
@@ -83,8 +83,10 @@
saRest = saRest[sizeofSockaddrInet6:]
} else if marshalFn != nil {
n := marshalFn(ms[i].Addr, saRest)
- sa = saRest[:n]
- saRest = saRest[n:]
+ if n > 0 {
+ sa = saRest[:n]
+ saRest = saRest[n:]
+ }
}
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
}
diff --git a/internal/socket/msghdr_linux.go b/internal/socket/msghdr_linux.go
index 5a38798..c3c7cc4 100644
--- a/internal/socket/msghdr_linux.go
+++ b/internal/socket/msghdr_linux.go
@@ -17,6 +17,9 @@
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
+ } else {
+ h.Name = nil
+ h.Namelen = 0
}
}
diff --git a/internal/socket/socket_test.go b/internal/socket/socket_test.go
index 96c6272..d37ca75 100644
--- a/internal/socket/socket_test.go
+++ b/internal/socket/socket_test.go
@@ -171,6 +171,16 @@
t.Fatal(err)
}
+ // create a dialed connection talking (only) to c/cc
+ cDialed, err := net.Dial("udp", c.LocalAddr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ ccDialed, err := socket.NewConn(cDialed)
+ if err != nil {
+ t.Fatal(err)
+ }
+
t.Run("Message", func(t *testing.T) {
data := []byte("HELLO-R-U-THERE")
wm := socket.Message{
@@ -191,6 +201,27 @@
t.Fatalf("got %#v; want %#v", b[:rm.N], data)
}
})
+ t.Run("Message-dialed", func(t *testing.T) {
+ data := []byte("HELLO-R-U-THERE")
+ wm := socket.Message{
+ Buffers: bytes.SplitAfter(data, []byte("-")),
+ Addr: nil,
+ }
+ if err := ccDialed.SendMsg(&wm, 0); err != nil {
+ t.Fatal(err)
+ }
+ b := make([]byte, 32)
+ rm := socket.Message{
+ Buffers: [][]byte{b[:1], b[1:3], b[3:7], b[7:11], b[11:]},
+ }
+ if err := cc.RecvMsg(&rm, 0); err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(b[:rm.N], data) {
+ t.Fatalf("got %#v; want %#v", b[:rm.N], data)
+ }
+ })
+
switch runtime.GOOS {
case "android", "linux":
t.Run("Messages", func(t *testing.T) {
@@ -228,6 +259,55 @@
t.Fatalf("got %#v; want %#v", b[:nn], data)
}
})
+ t.Run("Messages-undialed-no-dst", func(t *testing.T) {
+ // sending without destination address should fail.
+ // This checks that the internally recycled buffers are reset correctly.
+ data := []byte("HELLO-R-U-THERE")
+ wmbs := bytes.SplitAfter(data, []byte("-"))
+ wms := []socket.Message{
+ {Buffers: wmbs[:1], Addr: nil},
+ {Buffers: wmbs[1:], Addr: nil},
+ }
+ n, err := cc.SendMsgs(wms, 0)
+ if n != 0 && err == nil {
+ t.Fatal("expected error, destination address required")
+ }
+ })
+ t.Run("Messages-dialed", func(t *testing.T) {
+ data := []byte("HELLO-R-U-THERE")
+ wmbs := bytes.SplitAfter(data, []byte("-"))
+ wms := []socket.Message{
+ {Buffers: wmbs[:1], Addr: nil},
+ {Buffers: wmbs[1:], Addr: nil},
+ }
+ n, err := ccDialed.SendMsgs(wms, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != len(wms) {
+ t.Fatalf("got %d; want %d", n, len(wms))
+ }
+ b := make([]byte, 32)
+ rmbs := [][][]byte{{b[:len(wmbs[0])]}, {b[len(wmbs[0]):]}}
+ rms := []socket.Message{
+ {Buffers: rmbs[0]},
+ {Buffers: rmbs[1]},
+ }
+ n, err = cc.RecvMsgs(rms, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != len(rms) {
+ t.Fatalf("got %d; want %d", n, len(rms))
+ }
+ nn := 0
+ for i := 0; i < n; i++ {
+ nn += rms[i].N
+ }
+ if !bytes.Equal(b[:nn], data) {
+ t.Fatalf("got %#v; want %#v", b[:nn], data)
+ }
+ })
}
// The behavior of transmission for zero byte paylaod depends