The reconcile package is used for DOM reconcilation in Isomorphic Go web applications.

control.go 5.9KB

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