Commit 4d78cbea authored by Mikio Hara's avatar Mikio Hara

go.net/ipv6: restructure ancillary data socket option handling

This CL chops existing ancillary data socket option handlers and
puts them into platform dependent ancillary data socket option
binding table for code readability.

LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/164580043
parent 77024ba9
......@@ -7,145 +7,47 @@
package ipv6
import (
"net"
"os"
"syscall"
"unsafe"
)
const pktinfo = FlagDst | FlagInterface
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
if cf&FlagHopLimit != 0 {
if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
return err
}
if on {
opt.set(FlagHopLimit)
} else {
opt.clear(FlagHopLimit)
}
}
if cf&pktinfo != 0 {
if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
return err
}
if on {
opt.set(cf & pktinfo)
} else {
opt.clear(cf & pktinfo)
}
}
return nil
}
func newControlMessage(opt *rawOpt) (oob []byte) {
opt.Lock()
defer opt.Unlock()
l, off := 0, 0
if opt.isset(FlagHopLimit) {
l += syscall.CmsgSpace(4)
}
if opt.isset(pktinfo) {
l += syscall.CmsgSpace(sysSizeofPacketInfo)
}
if l > 0 {
oob = make([]byte, l)
if opt.isset(FlagHopLimit) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockopt2292HopLimit
m.SetLen(syscall.CmsgLen(4))
off += syscall.CmsgSpace(4)
}
if opt.isset(pktinfo) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockopt2292PacketInfo
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
off += syscall.CmsgSpace(sysSizeofPacketInfo)
}
func marshal2292HopLimit(b []byte, cm *ControlMessage) []byte {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
m.Level = ianaProtocolIPv6
m.Type = sysIPV6_2292HOPLIMIT
m.SetLen(syscall.CmsgLen(4))
if cm != nil {
data := b[syscall.CmsgLen(0):]
*(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.HopLimit)
}
return
return b[syscall.CmsgSpace(4):]
}
func parseControlMessage(b []byte) (*ControlMessage, error) {
if len(b) == 0 {
return nil, nil
}
cmsgs, err := syscall.ParseSocketControlMessage(b)
if err != nil {
return nil, os.NewSyscallError("parse socket control message", err)
}
cm := &ControlMessage{}
for _, m := range cmsgs {
if m.Header.Level != ianaProtocolIPv6 {
continue
func marshal2292PacketInfo(b []byte, cm *ControlMessage) []byte {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
m.Level = ianaProtocolIPv6
m.Type = sysIPV6_2292PKTINFO
m.SetLen(syscall.CmsgLen(sysSizeofInet6Pktinfo))
if cm != nil {
pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.Addr[:], ip)
}
switch m.Header.Type {
case sysSockopt2292HopLimit:
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
case sysSockopt2292PacketInfo:
pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
cm.IfIndex = int(pi.IfIndex)
cm.Dst = pi.IP[:]
if cm.IfIndex > 0 {
pi.setIfindex(cm.IfIndex)
}
}
return cm, nil
return b[syscall.CmsgSpace(sysSizeofInet6Pktinfo):]
}
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
if cm == nil {
return
}
l, off := 0, 0
if cm.HopLimit > 0 {
l += syscall.CmsgSpace(4)
}
pion := false
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
pion = true
l += syscall.CmsgSpace(sysSizeofPacketInfo)
}
if len(cm.NextHop) == net.IPv6len {
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
}
if l > 0 {
oob = make([]byte, l)
if cm.HopLimit > 0 {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockopt2292HopLimit
m.SetLen(syscall.CmsgLen(4))
data := oob[off+syscall.CmsgLen(0):]
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
off += syscall.CmsgSpace(4)
}
if pion {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockopt2292PacketInfo
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.IP[:], ip)
}
if cm.IfIndex != 0 {
pi.IfIndex = uint32(cm.IfIndex)
}
off += syscall.CmsgSpace(sysSizeofPacketInfo)
}
if len(cm.NextHop) == net.IPv6len {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockopt2292NextHop
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
setSockaddr(sa, cm.NextHop, cm.IfIndex)
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
}
func marshal2292NextHop(b []byte, cm *ControlMessage) []byte {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
m.Level = ianaProtocolIPv6
m.Type = sysIPV6_2292NEXTHOP
m.SetLen(syscall.CmsgLen(sysSizeofSockaddrInet6))
if cm != nil {
sa := (*sysSockaddrInet6)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
sa.setSockaddr(cm.NextHop, cm.IfIndex)
}
return
return b[syscall.CmsgSpace(sysSizeofSockaddrInet6):]
}
......@@ -2,209 +2,96 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build dragonfly freebsd linux netbsd openbsd
// +build darwin dragonfly freebsd linux netbsd openbsd
package ipv6
import (
"net"
"os"
"syscall"
"unsafe"
)
const pktinfo = FlagDst | FlagInterface
func marshalTrafficClass(b []byte, cm *ControlMessage) []byte {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
m.Level = ianaProtocolIPv6
m.Type = sysIPV6_TCLASS
m.SetLen(syscall.CmsgLen(4))
if cm != nil {
data := b[syscall.CmsgLen(0):]
*(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.TrafficClass)
}
return b[syscall.CmsgSpace(4):]
}
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
if cf&FlagTrafficClass != 0 {
if err := setIPv6ReceiveTrafficClass(fd, on); err != nil {
return err
}
if on {
opt.set(FlagTrafficClass)
} else {
opt.clear(FlagTrafficClass)
}
}
if cf&FlagHopLimit != 0 {
if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
return err
}
if on {
opt.set(FlagHopLimit)
} else {
opt.clear(FlagHopLimit)
}
}
if cf&pktinfo != 0 {
if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
return err
}
if on {
opt.set(cf & pktinfo)
} else {
opt.clear(cf & pktinfo)
}
}
if cf&FlagPathMTU != 0 {
if err := setIPv6ReceivePathMTU(fd, on); err != nil {
return err
}
if on {
opt.set(FlagPathMTU)
} else {
opt.clear(FlagPathMTU)
}
}
return nil
func parseTrafficClass(cm *ControlMessage, b []byte) {
cm.TrafficClass = int(*(*int32)(unsafe.Pointer(&b[:4][0])))
}
func newControlMessage(opt *rawOpt) (oob []byte) {
opt.Lock()
defer opt.Unlock()
l, off := 0, 0
if opt.isset(FlagTrafficClass) {
l += syscall.CmsgSpace(4)
}
if opt.isset(FlagHopLimit) {
l += syscall.CmsgSpace(4)
}
if opt.isset(pktinfo) {
l += syscall.CmsgSpace(sysSizeofPacketInfo)
}
if opt.isset(FlagPathMTU) {
l += syscall.CmsgSpace(sysSizeofMTUInfo)
}
if l > 0 {
oob = make([]byte, l)
if opt.isset(FlagTrafficClass) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockoptReceiveTrafficClass
m.SetLen(syscall.CmsgLen(4))
off += syscall.CmsgSpace(4)
}
if opt.isset(FlagHopLimit) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockoptReceiveHopLimit
m.SetLen(syscall.CmsgLen(4))
off += syscall.CmsgSpace(4)
}
if opt.isset(pktinfo) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockoptReceivePacketInfo
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
off += syscall.CmsgSpace(sysSizeofPacketInfo)
}
if opt.isset(FlagPathMTU) {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockoptReceivePathMTU
m.SetLen(syscall.CmsgLen(sysSizeofMTUInfo))
off += syscall.CmsgSpace(sysSizeofMTUInfo)
}
}
return
func marshalHopLimit(b []byte, cm *ControlMessage) []byte {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
m.Level = ianaProtocolIPv6
m.Type = sysIPV6_HOPLIMIT
m.SetLen(syscall.CmsgLen(4))
if cm != nil {
data := b[syscall.CmsgLen(0):]
*(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.HopLimit)
}
return b[syscall.CmsgSpace(4):]
}
func parseControlMessage(b []byte) (*ControlMessage, error) {
if len(b) == 0 {
return nil, nil
}
cmsgs, err := syscall.ParseSocketControlMessage(b)
if err != nil {
return nil, os.NewSyscallError("parse socket control message", err)
}
cm := &ControlMessage{}
for _, m := range cmsgs {
if m.Header.Level != ianaProtocolIPv6 {
continue
}
switch m.Header.Type {
case sysSockoptTrafficClass:
cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
case sysSockoptHopLimit:
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
case sysSockoptPacketInfo:
pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
cm.Dst = pi.IP[:]
cm.IfIndex = int(pi.IfIndex)
case sysSockoptPathMTU:
mi := (*sysMTUInfo)(unsafe.Pointer(&m.Data[0]))
cm.Dst = mi.Addr.Addr[:]
cm.IfIndex = int(mi.Addr.Scope_id)
cm.MTU = int(mi.MTU)
}
}
return cm, nil
func parseHopLimit(cm *ControlMessage, b []byte) {
cm.HopLimit = int(*(*int32)(unsafe.Pointer(&b[:4][0])))
}
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
if cm == nil {
return
}
l, off := 0, 0
if cm.TrafficClass > 0 {
l += syscall.CmsgSpace(4)
}
if cm.HopLimit > 0 {
l += syscall.CmsgSpace(4)
}
pion := false
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
pion = true
l += syscall.CmsgSpace(sysSizeofPacketInfo)
}
if len(cm.NextHop) == net.IPv6len {
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
}
if l > 0 {
oob = make([]byte, l)
if cm.TrafficClass > 0 {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockoptTrafficClass
m.SetLen(syscall.CmsgLen(4))
data := oob[off+syscall.CmsgLen(0):]
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
off += syscall.CmsgSpace(4)
}
if cm.HopLimit > 0 {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockoptHopLimit
m.SetLen(syscall.CmsgLen(4))
data := oob[off+syscall.CmsgLen(0):]
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
off += syscall.CmsgSpace(4)
func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
m.Level = ianaProtocolIPv6
m.Type = sysIPV6_PKTINFO
m.SetLen(syscall.CmsgLen(sysSizeofInet6Pktinfo))
if cm != nil {
pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.Addr[:], ip)
}
if pion {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockoptPacketInfo
m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.IP[:], ip)
}
if cm.IfIndex != 0 {
pi.IfIndex = uint32(cm.IfIndex)
}
off += syscall.CmsgSpace(sysSizeofPacketInfo)
}
if len(cm.NextHop) == net.IPv6len {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
m.Level = ianaProtocolIPv6
m.Type = sysSockoptNextHop
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
setSockaddr(sa, cm.NextHop, cm.IfIndex)
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
if cm.IfIndex > 0 {
pi.setIfindex(cm.IfIndex)
}
}
return
return b[syscall.CmsgSpace(sysSizeofInet6Pktinfo):]
}
func parsePacketInfo(cm *ControlMessage, b []byte) {
pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[0]))
cm.Dst = pi.Addr[:]
cm.IfIndex = int(pi.Ifindex)
}
func marshalNextHop(b []byte, cm *ControlMessage) []byte {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
m.Level = ianaProtocolIPv6
m.Type = sysIPV6_NEXTHOP
m.SetLen(syscall.CmsgLen(sysSizeofSockaddrInet6))
if cm != nil {
sa := (*sysSockaddrInet6)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
sa.setSockaddr(cm.NextHop, cm.IfIndex)
}
return b[syscall.CmsgSpace(sysSizeofSockaddrInet6):]
}
func parseNextHop(cm *ControlMessage, b []byte) {
}
func marshalPathMTU(b []byte, cm *ControlMessage) []byte {
m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
m.Level = ianaProtocolIPv6
m.Type = sysIPV6_PATHMTU
m.SetLen(syscall.CmsgLen(sysSizeofIPv6Mtuinfo))
return b[syscall.CmsgSpace(sysSizeofIPv6Mtuinfo):]
}
func parsePathMTU(cm *ControlMessage, b []byte) {
mi := (*sysIPv6Mtuinfo)(unsafe.Pointer(&b[0]))
cm.Dst = mi.Addr.Addr[:]
cm.IfIndex = int(mi.Addr.Scope_id)
cm.MTU = int(mi.Mtu)
}
// Copyright 2013 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.
// +build darwin dragonfly freebsd linux netbsd openbsd
package ipv6
import (
"os"
"syscall"
)
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 {
if err := setInt(fd, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagTrafficClass)
} else {
opt.clear(FlagTrafficClass)
}
}
if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 {
if err := setInt(fd, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagHopLimit)
} else {
opt.clear(FlagHopLimit)
}
}
if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 {
if err := setInt(fd, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil {
return err
}
if on {
opt.set(cf & flagPacketInfo)
} else {
opt.clear(cf & flagPacketInfo)
}
}
if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 {
if err := setInt(fd, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagPathMTU)
} else {
opt.clear(FlagPathMTU)
}
}
return nil
}
func newControlMessage(opt *rawOpt) (oob []byte) {
opt.RLock()
var l int
if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
}
if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
}
if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
}
if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
l += syscall.CmsgSpace(ctlOpts[ctlPathMTU].length)
}
if l > 0 {
oob = make([]byte, l)
b := oob
if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
b = ctlOpts[ctlTrafficClass].marshal(b, nil)
}
if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
b = ctlOpts[ctlHopLimit].marshal(b, nil)
}
if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
b = ctlOpts[ctlPacketInfo].marshal(b, nil)
}
if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
b = ctlOpts[ctlPathMTU].marshal(b, nil)
}
}
opt.RUnlock()
return
}
func parseControlMessage(b []byte) (*ControlMessage, error) {
if len(b) == 0 {
return nil, nil
}
cmsgs, err := syscall.ParseSocketControlMessage(b)
if err != nil {
return nil, os.NewSyscallError("parse socket control message", err)
}
cm := &ControlMessage{}
for _, m := range cmsgs {
if m.Header.Level != ianaProtocolIPv6 {
continue
}
switch int(m.Header.Type) {
case ctlOpts[ctlTrafficClass].name:
ctlOpts[ctlTrafficClass].parse(cm, m.Data[:])
case ctlOpts[ctlHopLimit].name:
ctlOpts[ctlHopLimit].parse(cm, m.Data[:])
case ctlOpts[ctlPacketInfo].name:
ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
case ctlOpts[ctlPathMTU].name:
ctlOpts[ctlPathMTU].parse(cm, m.Data[:])
}
}
return cm, nil
}
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
if cm == nil {
return
}
var l int
tclass := false
if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
tclass = true
l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
}
hoplimit := false
if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
hoplimit = true
l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
}
pktinfo := false
if ctlOpts[ctlPacketInfo].name > 0 && cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0 {
pktinfo = true
l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
}
nexthop := false
if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
nexthop = true
l += syscall.CmsgSpace(ctlOpts[ctlNextHop].length)
}
if l > 0 {
oob = make([]byte, l)
b := oob
if tclass {
b = ctlOpts[ctlTrafficClass].marshal(b, cm)
}
if hoplimit {
b = ctlOpts[ctlHopLimit].marshal(b, cm)
}
if pktinfo {
b = ctlOpts[ctlPacketInfo].marshal(b, cm)
}
if nexthop {
b = ctlOpts[ctlNextHop].marshal(b, cm)
}
}
return
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment