gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

control.go (6026B)


      1 // Copyright 2013 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 package ipv6
      6 
      7 import (
      8 	"fmt"
      9 	"net"
     10 	"sync"
     11 
     12 	"golang.org/x/net/internal/iana"
     13 	"golang.org/x/net/internal/socket"
     14 )
     15 
     16 // Note that RFC 3542 obsoletes RFC 2292 but OS X Snow Leopard and the
     17 // former still support RFC 2292 only. Please be aware that almost
     18 // all protocol implementations prohibit using a combination of RFC
     19 // 2292 and RFC 3542 for some practical reasons.
     20 
     21 type rawOpt struct {
     22 	sync.RWMutex
     23 	cflags ControlFlags
     24 }
     25 
     26 func (c *rawOpt) set(f ControlFlags)        { c.cflags |= f }
     27 func (c *rawOpt) clear(f ControlFlags)      { c.cflags &^= f }
     28 func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
     29 
     30 // A ControlFlags represents per packet basis IP-level socket option
     31 // control flags.
     32 type ControlFlags uint
     33 
     34 const (
     35 	FlagTrafficClass ControlFlags = 1 << iota // pass the traffic class on the received packet
     36 	FlagHopLimit                              // pass the hop limit on the received packet
     37 	FlagSrc                                   // pass the source address on the received packet
     38 	FlagDst                                   // pass the destination address on the received packet
     39 	FlagInterface                             // pass the interface index on the received packet
     40 	FlagPathMTU                               // pass the path MTU on the received packet path
     41 )
     42 
     43 const flagPacketInfo = FlagDst | FlagInterface
     44 
     45 // A ControlMessage represents per packet basis IP-level socket
     46 // options.
     47 type ControlMessage struct {
     48 	// Receiving socket options: SetControlMessage allows to
     49 	// receive the options from the protocol stack using ReadFrom
     50 	// method of PacketConn.
     51 	//
     52 	// Specifying socket options: ControlMessage for WriteTo
     53 	// method of PacketConn allows to send the options to the
     54 	// protocol stack.
     55 	//
     56 	TrafficClass int    // traffic class, must be 1 <= value <= 255 when specifying
     57 	HopLimit     int    // hop limit, must be 1 <= value <= 255 when specifying
     58 	Src          net.IP // source address, specifying only
     59 	Dst          net.IP // destination address, receiving only
     60 	IfIndex      int    // interface index, must be 1 <= value when specifying
     61 	NextHop      net.IP // next hop address, specifying only
     62 	MTU          int    // path MTU, receiving only
     63 }
     64 
     65 func (cm *ControlMessage) String() string {
     66 	if cm == nil {
     67 		return "<nil>"
     68 	}
     69 	return fmt.Sprintf("tclass=%#x hoplim=%d src=%v dst=%v ifindex=%d nexthop=%v mtu=%d", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU)
     70 }
     71 
     72 // Marshal returns the binary encoding of cm.
     73 func (cm *ControlMessage) Marshal() []byte {
     74 	if cm == nil {
     75 		return nil
     76 	}
     77 	var l int
     78 	tclass := false
     79 	if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
     80 		tclass = true
     81 		l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
     82 	}
     83 	hoplimit := false
     84 	if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
     85 		hoplimit = true
     86 		l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
     87 	}
     88 	pktinfo := false
     89 	if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
     90 		pktinfo = true
     91 		l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
     92 	}
     93 	nexthop := false
     94 	if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
     95 		nexthop = true
     96 		l += socket.ControlMessageSpace(ctlOpts[ctlNextHop].length)
     97 	}
     98 	var b []byte
     99 	if l > 0 {
    100 		b = make([]byte, l)
    101 		bb := b
    102 		if tclass {
    103 			bb = ctlOpts[ctlTrafficClass].marshal(bb, cm)
    104 		}
    105 		if hoplimit {
    106 			bb = ctlOpts[ctlHopLimit].marshal(bb, cm)
    107 		}
    108 		if pktinfo {
    109 			bb = ctlOpts[ctlPacketInfo].marshal(bb, cm)
    110 		}
    111 		if nexthop {
    112 			bb = ctlOpts[ctlNextHop].marshal(bb, cm)
    113 		}
    114 	}
    115 	return b
    116 }
    117 
    118 // Parse parses b as a control message and stores the result in cm.
    119 func (cm *ControlMessage) Parse(b []byte) error {
    120 	ms, err := socket.ControlMessage(b).Parse()
    121 	if err != nil {
    122 		return err
    123 	}
    124 	for _, m := range ms {
    125 		lvl, typ, l, err := m.ParseHeader()
    126 		if err != nil {
    127 			return err
    128 		}
    129 		if lvl != iana.ProtocolIPv6 {
    130 			continue
    131 		}
    132 		switch {
    133 		case typ == ctlOpts[ctlTrafficClass].name && l >= ctlOpts[ctlTrafficClass].length:
    134 			ctlOpts[ctlTrafficClass].parse(cm, m.Data(l))
    135 		case typ == ctlOpts[ctlHopLimit].name && l >= ctlOpts[ctlHopLimit].length:
    136 			ctlOpts[ctlHopLimit].parse(cm, m.Data(l))
    137 		case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
    138 			ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
    139 		case typ == ctlOpts[ctlPathMTU].name && l >= ctlOpts[ctlPathMTU].length:
    140 			ctlOpts[ctlPathMTU].parse(cm, m.Data(l))
    141 		}
    142 	}
    143 	return nil
    144 }
    145 
    146 // NewControlMessage returns a new control message.
    147 //
    148 // The returned message is large enough for options specified by cf.
    149 func NewControlMessage(cf ControlFlags) []byte {
    150 	opt := rawOpt{cflags: cf}
    151 	var l int
    152 	if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
    153 		l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
    154 	}
    155 	if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
    156 		l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
    157 	}
    158 	if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
    159 		l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
    160 	}
    161 	if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
    162 		l += socket.ControlMessageSpace(ctlOpts[ctlPathMTU].length)
    163 	}
    164 	var b []byte
    165 	if l > 0 {
    166 		b = make([]byte, l)
    167 	}
    168 	return b
    169 }
    170 
    171 // Ancillary data socket options
    172 const (
    173 	ctlTrafficClass = iota // header field
    174 	ctlHopLimit            // header field
    175 	ctlPacketInfo          // inbound or outbound packet path
    176 	ctlNextHop             // nexthop
    177 	ctlPathMTU             // path mtu
    178 	ctlMax
    179 )
    180 
    181 // A ctlOpt represents a binding for ancillary data socket option.
    182 type ctlOpt struct {
    183 	name    int // option name, must be equal or greater than 1
    184 	length  int // option length
    185 	marshal func([]byte, *ControlMessage) []byte
    186 	parse   func(*ControlMessage, []byte)
    187 }