ipld-eth-server/vendor/github.com/aristanetworks/goarista/dscp/tos_unix.go

67 lines
1.8 KiB
Go
Raw Normal View History

// Copyright (c) 2017 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.
package dscp
import (
"fmt"
"net"
"os"
"reflect"
"syscall"
"golang.org/x/sys/unix"
)
// This works for the UNIX implementation of netFD, i.e. not on Windows and Plan9.
// conn must either implement syscall.Conn or be a TCPListener.
func setTOS(ip net.IP, conn interface{}, tos byte) error {
var proto, optname int
if ip.To4() != nil {
proto = unix.IPPROTO_IP
optname = unix.IP_TOS
} else {
proto = unix.IPPROTO_IPV6
optname = unix.IPV6_TCLASS
}
switch c := conn.(type) {
case syscall.Conn:
return setTOSWithSyscallConn(proto, optname, c, tos)
case *net.TCPListener:
// This code is needed to support go1.9. In go1.10
// *net.TCPListener implements syscall.Conn.
return setTOSWithTCPListener(proto, optname, c, tos)
}
return fmt.Errorf("unsupported connection type: %T", conn)
}
func setTOSWithTCPListener(proto, optname int, conn *net.TCPListener, tos byte) error {
// A kludge for pre-go1.10 to get the fd of a net.TCPListener
value := reflect.ValueOf(conn)
netFD := value.Elem().FieldByName("fd").Elem()
fd := int(netFD.FieldByName("pfd").FieldByName("Sysfd").Int())
if err := unix.SetsockoptInt(fd, proto, optname, int(tos)); err != nil {
return os.NewSyscallError("setsockopt", err)
}
return nil
}
func setTOSWithSyscallConn(proto, optname int, conn syscall.Conn, tos byte) error {
syscallConn, err := conn.SyscallConn()
if err != nil {
return err
}
var setsockoptErr error
err = syscallConn.Control(func(fd uintptr) {
if err := unix.SetsockoptInt(int(fd), proto, optname, int(tos)); err != nil {
setsockoptErr = os.NewSyscallError("setsockopt", err)
}
})
if setsockoptErr != nil {
return setsockoptErr
}
return err
}