github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/ipv6/control_unix.go (about)

     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  // +build darwin dragonfly freebsd linux netbsd openbsd
     6  
     7  package ipv6
     8  
     9  import (
    10  	"os"
    11  	"syscall"
    12  
    13  	"golang.org/x/net/internal/iana"
    14  )
    15  
    16  func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
    17  	opt.Lock()
    18  	defer opt.Unlock()
    19  	if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 {
    20  		if err := setInt(fd, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil {
    21  			return err
    22  		}
    23  		if on {
    24  			opt.set(FlagTrafficClass)
    25  		} else {
    26  			opt.clear(FlagTrafficClass)
    27  		}
    28  	}
    29  	if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 {
    30  		if err := setInt(fd, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil {
    31  			return err
    32  		}
    33  		if on {
    34  			opt.set(FlagHopLimit)
    35  		} else {
    36  			opt.clear(FlagHopLimit)
    37  		}
    38  	}
    39  	if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 {
    40  		if err := setInt(fd, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil {
    41  			return err
    42  		}
    43  		if on {
    44  			opt.set(cf & flagPacketInfo)
    45  		} else {
    46  			opt.clear(cf & flagPacketInfo)
    47  		}
    48  	}
    49  	if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 {
    50  		if err := setInt(fd, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil {
    51  			return err
    52  		}
    53  		if on {
    54  			opt.set(FlagPathMTU)
    55  		} else {
    56  			opt.clear(FlagPathMTU)
    57  		}
    58  	}
    59  	return nil
    60  }
    61  
    62  func newControlMessage(opt *rawOpt) (oob []byte) {
    63  	opt.RLock()
    64  	var l int
    65  	if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
    66  		l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
    67  	}
    68  	if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
    69  		l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
    70  	}
    71  	if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
    72  		l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
    73  	}
    74  	if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
    75  		l += syscall.CmsgSpace(ctlOpts[ctlPathMTU].length)
    76  	}
    77  	if l > 0 {
    78  		oob = make([]byte, l)
    79  		b := oob
    80  		if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
    81  			b = ctlOpts[ctlTrafficClass].marshal(b, nil)
    82  		}
    83  		if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
    84  			b = ctlOpts[ctlHopLimit].marshal(b, nil)
    85  		}
    86  		if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
    87  			b = ctlOpts[ctlPacketInfo].marshal(b, nil)
    88  		}
    89  		if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
    90  			b = ctlOpts[ctlPathMTU].marshal(b, nil)
    91  		}
    92  	}
    93  	opt.RUnlock()
    94  	return
    95  }
    96  
    97  func parseControlMessage(b []byte) (*ControlMessage, error) {
    98  	if len(b) == 0 {
    99  		return nil, nil
   100  	}
   101  	cmsgs, err := syscall.ParseSocketControlMessage(b)
   102  	if err != nil {
   103  		return nil, os.NewSyscallError("parse socket control message", err)
   104  	}
   105  	cm := &ControlMessage{}
   106  	for _, m := range cmsgs {
   107  		if m.Header.Level != iana.ProtocolIPv6 {
   108  			continue
   109  		}
   110  		switch int(m.Header.Type) {
   111  		case ctlOpts[ctlTrafficClass].name:
   112  			ctlOpts[ctlTrafficClass].parse(cm, m.Data[:])
   113  		case ctlOpts[ctlHopLimit].name:
   114  			ctlOpts[ctlHopLimit].parse(cm, m.Data[:])
   115  		case ctlOpts[ctlPacketInfo].name:
   116  			ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
   117  		case ctlOpts[ctlPathMTU].name:
   118  			ctlOpts[ctlPathMTU].parse(cm, m.Data[:])
   119  		}
   120  	}
   121  	return cm, nil
   122  }
   123  
   124  func marshalControlMessage(cm *ControlMessage) (oob []byte) {
   125  	if cm == nil {
   126  		return
   127  	}
   128  	var l int
   129  	tclass := false
   130  	if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
   131  		tclass = true
   132  		l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
   133  	}
   134  	hoplimit := false
   135  	if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
   136  		hoplimit = true
   137  		l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
   138  	}
   139  	pktinfo := false
   140  	if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
   141  		pktinfo = true
   142  		l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
   143  	}
   144  	nexthop := false
   145  	if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
   146  		nexthop = true
   147  		l += syscall.CmsgSpace(ctlOpts[ctlNextHop].length)
   148  	}
   149  	if l > 0 {
   150  		oob = make([]byte, l)
   151  		b := oob
   152  		if tclass {
   153  			b = ctlOpts[ctlTrafficClass].marshal(b, cm)
   154  		}
   155  		if hoplimit {
   156  			b = ctlOpts[ctlHopLimit].marshal(b, cm)
   157  		}
   158  		if pktinfo {
   159  			b = ctlOpts[ctlPacketInfo].marshal(b, cm)
   160  		}
   161  		if nexthop {
   162  			b = ctlOpts[ctlNextHop].marshal(b, cm)
   163  		}
   164  	}
   165  	return
   166  }