1

I am working on an embedded system that uses GO v1.13 on the build server. My goal is to make a CANbus manager using linux's socketCAN. Go has a can-go package that is perfect for this solution. However, the package uses the "golang.org/x/sys/" package that uses the unsafe.Slice that was added in Go v1.17. I am unable to upgrade my version to a supported go version.

To solve this issue, I am making my own package that is very similar to can-go but uses syscall.socket instead of unix.socket.

The issue that I have ran into is with the implementation of syscall.Sockaddr. I have implemented it identically to the can-go package but I am getting the following terminal output.

.\canSocket.go:91:42: cannot use &SockaddrCAN literal (type *SockaddrCAN) as type syscall.Sockaddr in argument to syscall.Bind:
        *SockaddrCAN does not implement syscall.Sockaddr (missing syscall.sockaddr method)
                have sockaddr() (unsafe.Pointer, int32, error)
                want syscall.sockaddr() (unsafe.Pointer, int32, error)

I must be missing something very obvious as this looks to be the standard "you are incorrectly implementing an interface" message. I am very new to GO and am expecting that I have missed something fundamental. Can anyone see what I did wrong? Below is the relevant section of my code.

func DialRaw(device string) (net.Conn, error) {
    var err error
    defer func() {
        if err != nil {
            err = &net.OpError{Op: "dial", Net: canRawNetwork, Addr: &canRawAddr{device: device}, Err: err}
        }
    }()
    ifi, err := net.InterfaceByName(device)
    if err != nil {
        return nil, fmt.Errorf("interface %s: %w", device, err)
    }
    fd, err := syscall.Socket(AF_CAN, SOCK_RAW, CAN_RAW)
    if err != nil {
        return nil, fmt.Errorf("socket: %w", err)
    }
    // put fd in non-blocking mode so the created file will be registered by the runtime poller (Go >= 1.12)
    if err := syscall.SetNonblock(fd, true); err != nil {
        return nil, fmt.Errorf("set nonblock: %w", err)
    }
    if err := syscall.Bind(fd, &SockaddrCAN{Ifindex: ifi.Index}); err != nil {
        return nil, fmt.Errorf("bind: %w", err)
    }
    return &fileConn{ra: &canRawAddr{device: device}, f: os.NewFile(uintptr(fd), "can")}, nil
}

type RawSockaddrCAN struct {
    Family  uint16
    Ifindex int32
    Addr    [16]byte
}

type SockaddrCAN struct {
    Ifindex int
    RxID    uint32
    TxID    uint32
    raw     RawSockaddrCAN
}

func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, int32, error) {
    if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
        return nil, 0, EINVAL
    }
    sa.raw.Family = AF_CAN
    sa.raw.Ifindex = int32(sa.Ifindex)
    rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
    for i := 0; i < 4; i++ {
        sa.raw.Addr[i] = rx[i]
    }
    tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
    for i := 0; i < 4; i++ {
        sa.raw.Addr[i+4] = tx[i]
    }
    return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
}
Michael T
  • 11
  • 2
  • you can't implement an unexported method https://stackoverflow.com/questions/26181271/is-it-possible-to-implement-an-interface-with-unexported-methods-in-another-pack – blackgreen Oct 06 '22 at 14:19
  • @blackgreen This means that I have to use "golang.org/x/sys/" instead of syscall because this interface must be implemented inside the package and syscall does not have the implementation? – Michael T Oct 06 '22 at 15:27
  • it means that you can't implement `syscall.Sockaddr`, except by embedding it. However `einride/can-go` declares its go.mod with `go 1.13`. You should specify in your question exactly which package you're using. And also, check if they have older releases that don't depend on newer versions of `x/sys` – blackgreen Oct 06 '22 at 19:39

0 Answers0