Skip to content

Commit b8b1343

Browse files
committed
internal/socket: add message IO functionality
This change adds portable message IO methods of Conn, IO message and control message types, and parse methods for the types to provide those functionality to the ipv4 and ipv6 packages. With this change, the ipv4 and ipv6 packages can provide low-level (but less heap allocation and the cost of invoking system calls) API such as read and write operations for a batch of IO messages. On vanilla linux/amd64 virtual machine: BenchmarkUDP/Iter-1-2 1000000 8068 ns/op 408 B/op 14 allocs/op BenchmarkUDP/Batch-1-2 1000000 8610 ns/op 440 B/op 14 allocs/op BenchmarkUDP/Iter-2-2 500000 15390 ns/op 816 B/op 28 allocs/op BenchmarkUDP/Batch-2-2 500000 12715 ns/op 696 B/op 20 allocs/op BenchmarkUDP/Iter-4-2 200000 30763 ns/op 1632 B/op 56 allocs/op BenchmarkUDP/Batch-4-2 300000 21853 ns/op 1216 B/op 32 allocs/op BenchmarkUDP/Iter-8-2 100000 61460 ns/op 3264 B/op 112 allocs/op BenchmarkUDP/Batch-8-2 200000 39048 ns/op 2256 B/op 56 allocs/op BenchmarkUDP/Iter-16-2 50000 122408 ns/op 6528 B/op 224 allocs/op BenchmarkUDP/Batch-16-2 100000 72728 ns/op 4336 B/op 104 allocs/op BenchmarkUDP/Iter-32-2 30000 243137 ns/op 13056 B/op 448 allocs/op BenchmarkUDP/Batch-32-2 50000 141332 ns/op 8496 B/op 200 allocs/op BenchmarkUDP/Iter-64-2 20000 488125 ns/op 26112 B/op 896 allocs/op BenchmarkUDP/Batch-64-2 30000 282078 ns/op 16816 B/op 392 allocs/op BenchmarkUDP/Iter-128-2 10000 973752 ns/op 52224 B/op 1792 allocs/op BenchmarkUDP/Batch-128-2 10000 551021 ns/op 33456 B/op 776 allocs/op BenchmarkUDP/Iter-256-2 3000 1977852 ns/op 104448 B/op 3584 allocs/op BenchmarkUDP/Batch-256-2 10000 1252596 ns/op 66736 B/op 1544 allocs/op BenchmarkUDP/Iter-512-2 2000 4147495 ns/op 208896 B/op 7168 allocs/op BenchmarkUDP/Batch-512-2 3000 2175774 ns/op 121128 B/op 2612 allocs/op Change-Id: I3e08b28917b62dbea7936a86acb24e25ccaf5365 Reviewed-on: https://go-review.googlesource.com/38212 Run-TryBot: Mikio Hara <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent f61a773 commit b8b1343

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1602
-9
lines changed

internal/socket/cmsghdr.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2017 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+
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
6+
7+
package socket
8+
9+
func (h *cmsghdr) len() int { return int(h.Len) }
10+
func (h *cmsghdr) lvl() int { return int(h.Level) }
11+
func (h *cmsghdr) typ() int { return int(h.Type) }

internal/socket/cmsghdr_bsd.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2017 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+
// +build darwin dragonfly freebsd netbsd openbsd
6+
7+
package socket
8+
9+
func (h *cmsghdr) set(l, lvl, typ int) {
10+
h.Len = uint32(l)
11+
h.Level = int32(lvl)
12+
h.Type = int32(typ)
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2017 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+
// +build arm mips mipsle 386
6+
// +build linux
7+
8+
package socket
9+
10+
func (h *cmsghdr) set(l, lvl, typ int) {
11+
h.Len = uint32(l)
12+
h.Level = int32(lvl)
13+
h.Type = int32(typ)
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2017 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+
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
6+
// +build linux
7+
8+
package socket
9+
10+
func (h *cmsghdr) set(l, lvl, typ int) {
11+
h.Len = uint64(l)
12+
h.Level = int32(lvl)
13+
h.Type = int32(typ)
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2017 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+
// +build amd64
6+
// +build solaris
7+
8+
package socket
9+
10+
func (h *cmsghdr) set(l, lvl, typ int) {
11+
h.Len = uint32(l)
12+
h.Level = int32(lvl)
13+
h.Type = int32(typ)
14+
}

internal/socket/cmsghdr_stub.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2017 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+
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
6+
7+
package socket
8+
9+
type cmsghdr struct{}
10+
11+
const sizeofCmsghdr = 0
12+
13+
func (h *cmsghdr) len() int { return 0 }
14+
func (h *cmsghdr) lvl() int { return 0 }
15+
func (h *cmsghdr) typ() int { return 0 }
16+
17+
func (h *cmsghdr) set(l, lvl, typ int) {}

internal/socket/iovec_32bit.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 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+
// +build arm mips mipsle 386
6+
// +build darwin dragonfly freebsd linux netbsd openbsd
7+
8+
package socket
9+
10+
import "unsafe"
11+
12+
func (v *iovec) set(b []byte) {
13+
v.Base = (*byte)(unsafe.Pointer(&b[0]))
14+
v.Len = uint32(len(b))
15+
}

internal/socket/iovec_64bit.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 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+
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
6+
// +build darwin dragonfly freebsd linux netbsd openbsd
7+
8+
package socket
9+
10+
import "unsafe"
11+
12+
func (v *iovec) set(b []byte) {
13+
v.Base = (*byte)(unsafe.Pointer(&b[0]))
14+
v.Len = uint64(len(b))
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 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+
// +build amd64
6+
// +build solaris
7+
8+
package socket
9+
10+
import "unsafe"
11+
12+
func (v *iovec) set(b []byte) {
13+
v.Base = (*int8)(unsafe.Pointer(&b[0]))
14+
v.Len = uint64(len(b))
15+
}

internal/socket/iovec_stub.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2017 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+
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
6+
7+
package socket
8+
9+
type iovec struct{}
10+
11+
func (v *iovec) set(b []byte) {}

internal/socket/mmsghdr_stub.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 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+
// +build !linux,!netbsd
6+
7+
package socket
8+
9+
import "net"
10+
11+
type mmsghdr struct{}
12+
13+
type mmsghdrs []mmsghdr
14+
15+
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
16+
return nil
17+
}
18+
19+
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
20+
return nil
21+
}

internal/socket/mmsghdr_unix.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2017 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+
// +build linux netbsd
6+
7+
package socket
8+
9+
import "net"
10+
11+
type mmsghdrs []mmsghdr
12+
13+
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
14+
for i := range hs {
15+
vs := make([]iovec, len(ms[i].Buffers))
16+
var sa []byte
17+
if parseFn != nil {
18+
sa = make([]byte, sizeofSockaddrInet6)
19+
}
20+
if marshalFn != nil {
21+
sa = marshalFn(ms[i].Addr)
22+
}
23+
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
24+
}
25+
return nil
26+
}
27+
28+
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
29+
for i := range hs {
30+
ms[i].N = int(hs[i].Len)
31+
ms[i].NN = hs[i].Hdr.controllen()
32+
ms[i].Flags = hs[i].Hdr.flags()
33+
if parseFn != nil {
34+
var err error
35+
ms[i].Addr, err = parseFn(hs[i].Hdr.name(), hint)
36+
if err != nil {
37+
return err
38+
}
39+
}
40+
}
41+
return nil
42+
}

internal/socket/msghdr_bsd.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2017 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+
// +build darwin dragonfly freebsd netbsd openbsd
6+
7+
package socket
8+
9+
import "unsafe"
10+
11+
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
12+
for i := range vs {
13+
vs[i].set(bs[i])
14+
}
15+
h.setIov(vs)
16+
if len(oob) > 0 {
17+
h.Control = (*byte)(unsafe.Pointer(&oob[0]))
18+
h.Controllen = uint32(len(oob))
19+
}
20+
if sa != nil {
21+
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
22+
h.Namelen = uint32(len(sa))
23+
}
24+
}
25+
26+
func (h *msghdr) name() []byte {
27+
if h.Name != nil && h.Namelen > 0 {
28+
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
29+
}
30+
return nil
31+
}
32+
33+
func (h *msghdr) controllen() int {
34+
return int(h.Controllen)
35+
}
36+
37+
func (h *msghdr) flags() int {
38+
return int(h.Flags)
39+
}

internal/socket/msghdr_bsdvar.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2017 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+
// +build darwin dragonfly freebsd netbsd
6+
7+
package socket
8+
9+
func (h *msghdr) setIov(vs []iovec) {
10+
h.Iov = &vs[0]
11+
h.Iovlen = int32(len(vs))
12+
}

internal/socket/msghdr_linux.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2017 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+
package socket
6+
7+
import "unsafe"
8+
9+
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
10+
for i := range vs {
11+
vs[i].set(bs[i])
12+
}
13+
h.setIov(vs)
14+
if len(oob) > 0 {
15+
h.setControl(oob)
16+
}
17+
if sa != nil {
18+
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
19+
h.Namelen = uint32(len(sa))
20+
}
21+
}
22+
23+
func (h *msghdr) name() []byte {
24+
if h.Name != nil && h.Namelen > 0 {
25+
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
26+
}
27+
return nil
28+
}
29+
30+
func (h *msghdr) controllen() int {
31+
return int(h.Controllen)
32+
}
33+
34+
func (h *msghdr) flags() int {
35+
return int(h.Flags)
36+
}

internal/socket/msghdr_linux_32bit.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 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+
// +build arm mips mipsle 386
6+
// +build linux
7+
8+
package socket
9+
10+
import "unsafe"
11+
12+
func (h *msghdr) setIov(vs []iovec) {
13+
h.Iov = &vs[0]
14+
h.Iovlen = uint32(len(vs))
15+
}
16+
17+
func (h *msghdr) setControl(b []byte) {
18+
h.Control = (*byte)(unsafe.Pointer(&b[0]))
19+
h.Controllen = uint32(len(b))
20+
}

internal/socket/msghdr_linux_64bit.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 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+
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le s390x
6+
// +build linux
7+
8+
package socket
9+
10+
import "unsafe"
11+
12+
func (h *msghdr) setIov(vs []iovec) {
13+
h.Iov = &vs[0]
14+
h.Iovlen = uint64(len(vs))
15+
}
16+
17+
func (h *msghdr) setControl(b []byte) {
18+
h.Control = (*byte)(unsafe.Pointer(&b[0]))
19+
h.Controllen = uint64(len(b))
20+
}

internal/socket/msghdr_openbsd.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright 2017 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+
package socket
6+
7+
func (h *msghdr) setIov(vs []iovec) {
8+
h.Iov = &vs[0]
9+
h.Iovlen = uint32(len(vs))
10+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2017 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+
// +build amd64
6+
// +build solaris
7+
8+
package socket
9+
10+
import "unsafe"
11+
12+
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
13+
for i := range vs {
14+
vs[i].set(bs[i])
15+
}
16+
h.Iov = &vs[0]
17+
h.Iovlen = int32(len(vs))
18+
if len(oob) > 0 {
19+
h.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
20+
h.Accrightslen = int32(len(oob))
21+
}
22+
if sa != nil {
23+
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
24+
h.Namelen = uint32(len(sa))
25+
}
26+
}
27+
28+
func (h *msghdr) controllen() int {
29+
return int(h.Accrightslen)
30+
}
31+
32+
func (h *msghdr) flags() int {
33+
return int(NativeEndian.Uint32(h.Pad_cgo_2[:]))
34+
}

0 commit comments

Comments
 (0)