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 }