123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- // 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.
- //go:build aix || linux || netbsd
- // +build aix linux netbsd
- package socket
- import (
- "net"
- "sync"
- )
- 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
- }
- // 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)
- }
|