2021-01-24 23:37:35 +00:00
|
|
|
// Copyright 2017 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2021-02-28 23:08:33 +00:00
|
|
|
//go:build aix || linux || netbsd
|
2021-01-24 23:37:35 +00:00
|
|
|
// +build aix linux netbsd
|
|
|
|
|
|
|
|
package socket
|
|
|
|
|
2021-06-10 14:44:25 +00:00
|
|
|
import (
|
|
|
|
"net"
|
|
|
|
"sync"
|
|
|
|
)
|
2021-01-24 23:37:35 +00:00
|
|
|
|
|
|
|
type mmsghdrs []mmsghdr
|
|
|
|
|
|
|
|
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
|
|
|
|
for i := range hs {
|
|
|
|
ms[i].N = int(hs[i].Len)
|
|
|
|
ms[i].NN = hs[i].Hdr.controllen()
|
|
|
|
ms[i].Flags = hs[i].Hdr.flags()
|
|
|
|
if parseFn != nil {
|
|
|
|
var err error
|
|
|
|
ms[i].Addr, err = parseFn(hs[i].Hdr.name(), hint)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2021-06-10 14:44:25 +00:00
|
|
|
|
|
|
|
// mmsghdrsPacker packs Message-slices into mmsghdrs (re-)using pre-allocated buffers.
|
|
|
|
type mmsghdrsPacker struct {
|
|
|
|
// hs are the pre-allocated mmsghdrs.
|
|
|
|
hs mmsghdrs
|
|
|
|
// sockaddrs is the pre-allocated buffer for the Hdr.Name buffers.
|
|
|
|
// We use one large buffer for all messages and slice it up.
|
|
|
|
sockaddrs []byte
|
|
|
|
// vs are the pre-allocated iovecs.
|
|
|
|
// We allocate one large buffer for all messages and slice it up. This allows to reuse the buffer
|
|
|
|
// if the number of buffers per message is distributed differently between calls.
|
|
|
|
vs []iovec
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *mmsghdrsPacker) prepare(ms []Message) {
|
|
|
|
n := len(ms)
|
|
|
|
if n <= cap(p.hs) {
|
|
|
|
p.hs = p.hs[:n]
|
|
|
|
} else {
|
|
|
|
p.hs = make(mmsghdrs, n)
|
|
|
|
}
|
|
|
|
if n*sizeofSockaddrInet6 <= cap(p.sockaddrs) {
|
|
|
|
p.sockaddrs = p.sockaddrs[:n*sizeofSockaddrInet6]
|
|
|
|
} else {
|
|
|
|
p.sockaddrs = make([]byte, n*sizeofSockaddrInet6)
|
|
|
|
}
|
|
|
|
|
|
|
|
nb := 0
|
|
|
|
for _, m := range ms {
|
|
|
|
nb += len(m.Buffers)
|
|
|
|
}
|
|
|
|
if nb <= cap(p.vs) {
|
|
|
|
p.vs = p.vs[:nb]
|
|
|
|
} else {
|
|
|
|
p.vs = make([]iovec, nb)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *mmsghdrsPacker) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr, []byte) int) mmsghdrs {
|
|
|
|
p.prepare(ms)
|
|
|
|
hs := p.hs
|
|
|
|
vsRest := p.vs
|
|
|
|
saRest := p.sockaddrs
|
|
|
|
for i := range hs {
|
|
|
|
nvs := len(ms[i].Buffers)
|
|
|
|
vs := vsRest[:nvs]
|
|
|
|
vsRest = vsRest[nvs:]
|
|
|
|
|
|
|
|
var sa []byte
|
|
|
|
if parseFn != nil {
|
|
|
|
sa = saRest[:sizeofSockaddrInet6]
|
|
|
|
saRest = saRest[sizeofSockaddrInet6:]
|
|
|
|
} else if marshalFn != nil {
|
|
|
|
n := marshalFn(ms[i].Addr, saRest)
|
|
|
|
if n > 0 {
|
|
|
|
sa = saRest[:n]
|
|
|
|
saRest = saRest[n:]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
|
|
|
|
}
|
|
|
|
return hs
|
|
|
|
}
|
|
|
|
|
|
|
|
var defaultMmsghdrsPool = mmsghdrsPool{
|
|
|
|
p: sync.Pool{
|
|
|
|
New: func() interface{} {
|
|
|
|
return new(mmsghdrsPacker)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
type mmsghdrsPool struct {
|
|
|
|
p sync.Pool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *mmsghdrsPool) Get() *mmsghdrsPacker {
|
|
|
|
return p.p.Get().(*mmsghdrsPacker)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *mmsghdrsPool) Put(packer *mmsghdrsPacker) {
|
|
|
|
p.p.Put(packer)
|
|
|
|
}
|