gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/net/internal/socket/mmsghdr_unix.go (about)

     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  //go:build aix || linux || netbsd
     6  // +build aix linux netbsd
     7  
     8  package socket
     9  
    10  import (
    11  	"net"
    12  	"os"
    13  	"sync"
    14  	"syscall"
    15  )
    16  
    17  type mmsghdrs []mmsghdr
    18  
    19  func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
    20  	for i := range hs {
    21  		ms[i].N = int(hs[i].Len)
    22  		ms[i].NN = hs[i].Hdr.controllen()
    23  		ms[i].Flags = hs[i].Hdr.flags()
    24  		if parseFn != nil {
    25  			var err error
    26  			ms[i].Addr, err = parseFn(hs[i].Hdr.name(), hint)
    27  			if err != nil {
    28  				return err
    29  			}
    30  		}
    31  	}
    32  	return nil
    33  }
    34  
    35  // mmsghdrsPacker packs Message-slices into mmsghdrs (re-)using pre-allocated buffers.
    36  type mmsghdrsPacker struct {
    37  	// hs are the pre-allocated mmsghdrs.
    38  	hs mmsghdrs
    39  	// sockaddrs is the pre-allocated buffer for the Hdr.Name buffers.
    40  	// We use one large buffer for all messages and slice it up.
    41  	sockaddrs []byte
    42  	// vs are the pre-allocated iovecs.
    43  	// We allocate one large buffer for all messages and slice it up. This allows to reuse the buffer
    44  	// if the number of buffers per message is distributed differently between calls.
    45  	vs []iovec
    46  }
    47  
    48  func (p *mmsghdrsPacker) prepare(ms []Message) {
    49  	n := len(ms)
    50  	if n <= cap(p.hs) {
    51  		p.hs = p.hs[:n]
    52  	} else {
    53  		p.hs = make(mmsghdrs, n)
    54  	}
    55  	if n*sizeofSockaddrInet6 <= cap(p.sockaddrs) {
    56  		p.sockaddrs = p.sockaddrs[:n*sizeofSockaddrInet6]
    57  	} else {
    58  		p.sockaddrs = make([]byte, n*sizeofSockaddrInet6)
    59  	}
    60  
    61  	nb := 0
    62  	for _, m := range ms {
    63  		nb += len(m.Buffers)
    64  	}
    65  	if nb <= cap(p.vs) {
    66  		p.vs = p.vs[:nb]
    67  	} else {
    68  		p.vs = make([]iovec, nb)
    69  	}
    70  }
    71  
    72  func (p *mmsghdrsPacker) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr, []byte) int) mmsghdrs {
    73  	p.prepare(ms)
    74  	hs := p.hs
    75  	vsRest := p.vs
    76  	saRest := p.sockaddrs
    77  	for i := range hs {
    78  		nvs := len(ms[i].Buffers)
    79  		vs := vsRest[:nvs]
    80  		vsRest = vsRest[nvs:]
    81  
    82  		var sa []byte
    83  		if parseFn != nil {
    84  			sa = saRest[:sizeofSockaddrInet6]
    85  			saRest = saRest[sizeofSockaddrInet6:]
    86  		} else if marshalFn != nil {
    87  			n := marshalFn(ms[i].Addr, saRest)
    88  			if n > 0 {
    89  				sa = saRest[:n]
    90  				saRest = saRest[n:]
    91  			}
    92  		}
    93  		hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
    94  	}
    95  	return hs
    96  }
    97  
    98  // syscaller is a helper to invoke recvmmsg and sendmmsg via the RawConn.Read/Write interface.
    99  // It is reusable, to amortize the overhead of allocating a closure for the function passed to
   100  // RawConn.Read/Write.
   101  type syscaller struct {
   102  	n     int
   103  	operr error
   104  	hs    mmsghdrs
   105  	flags int
   106  
   107  	boundRecvmmsgF func(uintptr) bool
   108  	boundSendmmsgF func(uintptr) bool
   109  }
   110  
   111  func (r *syscaller) init() {
   112  	r.boundRecvmmsgF = r.recvmmsgF
   113  	r.boundSendmmsgF = r.sendmmsgF
   114  }
   115  
   116  func (r *syscaller) recvmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
   117  	r.n = 0
   118  	r.operr = nil
   119  	r.hs = hs
   120  	r.flags = flags
   121  	if err := c.Read(r.boundRecvmmsgF); err != nil {
   122  		return r.n, err
   123  	}
   124  	if r.operr != nil {
   125  		return r.n, os.NewSyscallError("recvmmsg", r.operr)
   126  	}
   127  	return r.n, nil
   128  }
   129  
   130  func (r *syscaller) recvmmsgF(s uintptr) bool {
   131  	r.n, r.operr = recvmmsg(s, r.hs, r.flags)
   132  	return ioComplete(r.flags, r.operr)
   133  }
   134  
   135  func (r *syscaller) sendmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
   136  	r.n = 0
   137  	r.operr = nil
   138  	r.hs = hs
   139  	r.flags = flags
   140  	if err := c.Write(r.boundSendmmsgF); err != nil {
   141  		return r.n, err
   142  	}
   143  	if r.operr != nil {
   144  		return r.n, os.NewSyscallError("sendmmsg", r.operr)
   145  	}
   146  	return r.n, nil
   147  }
   148  
   149  func (r *syscaller) sendmmsgF(s uintptr) bool {
   150  	r.n, r.operr = sendmmsg(s, r.hs, r.flags)
   151  	return ioComplete(r.flags, r.operr)
   152  }
   153  
   154  // mmsgTmps holds reusable temporary helpers for recvmmsg and sendmmsg.
   155  type mmsgTmps struct {
   156  	packer    mmsghdrsPacker
   157  	syscaller syscaller
   158  }
   159  
   160  var defaultMmsgTmpsPool = mmsgTmpsPool{
   161  	p: sync.Pool{
   162  		New: func() interface{} {
   163  			tmps := new(mmsgTmps)
   164  			tmps.syscaller.init()
   165  			return tmps
   166  		},
   167  	},
   168  }
   169  
   170  type mmsgTmpsPool struct {
   171  	p sync.Pool
   172  }
   173  
   174  func (p *mmsgTmpsPool) Get() *mmsgTmps {
   175  	return p.p.Get().(*mmsgTmps)
   176  }
   177  
   178  func (p *mmsgTmpsPool) Put(tmps *mmsgTmps) {
   179  	p.p.Put(tmps)
   180  }