package socket
import (
"net"
"os"
"sync"
"syscall"
)
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
}
type mmsghdrsPacker struct {
hs mmsghdrs
sockaddrs []byte
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
}
type syscaller struct {
n int
operr error
hs mmsghdrs
flags int
boundRecvmmsgF func (uintptr ) bool
boundSendmmsgF func (uintptr ) bool
}
func (r *syscaller ) init () {
r .boundRecvmmsgF = r .recvmmsgF
r .boundSendmmsgF = r .sendmmsgF
}
func (r *syscaller ) recvmmsg (c syscall .RawConn , hs mmsghdrs , flags int ) (int , error ) {
r .n = 0
r .operr = nil
r .hs = hs
r .flags = flags
if err := c .Read (r .boundRecvmmsgF ); err != nil {
return r .n , err
}
if r .operr != nil {
return r .n , os .NewSyscallError ("recvmmsg" , r .operr )
}
return r .n , nil
}
func (r *syscaller ) recvmmsgF (s uintptr ) bool {
r .n , r .operr = recvmmsg (s , r .hs , r .flags )
return ioComplete (r .flags , r .operr )
}
func (r *syscaller ) sendmmsg (c syscall .RawConn , hs mmsghdrs , flags int ) (int , error ) {
r .n = 0
r .operr = nil
r .hs = hs
r .flags = flags
if err := c .Write (r .boundSendmmsgF ); err != nil {
return r .n , err
}
if r .operr != nil {
return r .n , os .NewSyscallError ("sendmmsg" , r .operr )
}
return r .n , nil
}
func (r *syscaller ) sendmmsgF (s uintptr ) bool {
r .n , r .operr = sendmmsg (s , r .hs , r .flags )
return ioComplete (r .flags , r .operr )
}
type mmsgTmps struct {
packer mmsghdrsPacker
syscaller syscaller
}
var defaultMmsgTmpsPool = mmsgTmpsPool {
p : sync .Pool {
New : func () interface {} {
tmps := new (mmsgTmps )
tmps .syscaller .init ()
return tmps
},
},
}
type mmsgTmpsPool struct {
p sync .Pool
}
func (p *mmsgTmpsPool ) Get () *mmsgTmps {
m := p .p .Get ().(*mmsgTmps )
for i := range m .packer .sockaddrs {
m .packer .sockaddrs [i ] = 0
}
m .packer .sockaddrs = m .packer .sockaddrs [:0 ]
for i := range m .packer .vs {
m .packer .vs [i ] = iovec {}
}
m .packer .vs = m .packer .vs [:0 ]
for i := range m .packer .hs {
m .packer .hs [i ].Len = 0
m .packer .hs [i ].Hdr = msghdr {}
}
m .packer .hs = m .packer .hs [:0 ]
return m
}
func (p *mmsgTmpsPool ) Put (tmps *mmsgTmps ) {
p .p .Put (tmps )
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .