package socket
import (
"encoding/binary"
"errors"
"net"
"syscall"
"golang.org/x/sys/unix"
)
func (m *MagicConn ) WriteMsgUDP (p , oob []byte , addr *net .UDPAddr ) (n , oobn int , err error ) {
segmentSize := udpSegmentSize (oob )
if m .sock .IsClosed () {
return len (p ), len (oob ), nil
}
ap := canonicalAddrPort (addr .AddrPort ())
if m .transports .ip == nil || (!isDefinitelyIP (ap .Addr ()) && Classify (ap .Addr ()) != KindIP ) {
m .writeMsgSegments (p , addr , segmentSize )
return len (p ), len (oob ), nil
}
n , oobn , err = m .udp .WriteMsgUDPAddrPort (p , oob , ap )
if err == nil {
for range segmentCount (len (p ), segmentSize ) {
m .recordIPSent (ap )
}
return n , oobn , nil
}
if segmentSize > 0 && errors .Is (err , unix .EIO ) {
return n , oobn , err
}
m .metrics .blackholed .Add (uint64 (segmentCount (len (p ), segmentSize )))
return len (p ), len (oob ), nil
}
func (m *MagicConn ) writeMsgSegments (p []byte , addr *net .UDPAddr , segmentSize int ) {
if segmentSize <= 0 {
m .WriteTo (p , addr )
return
}
for len (p ) > 0 {
n := min (len (p ), segmentSize )
m .WriteTo (p [:n ], addr )
p = p [n :]
}
}
func segmentCount(n , segmentSize int ) int {
if segmentSize <= 0 {
return 1
}
return (n + segmentSize - 1 ) / segmentSize
}
func udpSegmentSize(oob []byte ) int {
for len (oob ) > 0 {
header , data , remainder , err := unix .ParseOneSocketControlMessage (oob )
if err != nil {
return 0
}
if header .Level == syscall .IPPROTO_UDP && header .Type == unix .UDP_SEGMENT && len (data ) >= 2 {
return int (binary .NativeEndian .Uint16 (data ))
}
oob = remainder
}
return 0
}
The pages are generated with Golds v0.8.4 . (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 .