Skip to content

proposal: x/sys: permit custom socket implementations #54209

Description

@x1unix

Brief intro

Hello.

I'm working on VmWare vSockets / VMCI library port from C to Go.

vSockets (previously known as VMCI) are vendor-specific sockets (similar to vsock in Linux) that allow hypervisor and guest communication.
On host side, these sockets behave like regular sockets. The only difference is different socket family number and special sockaddr structure.
socket(), accept() and other methods behave the same.

The problem

I tried to utilize standard methods from syscall package like syscall.Bind and syscall.Accept which behave like eponymous methods from libc but have some extra glue code.

The simplest solution was to import vmci_sockets.h header use cgo but I remember how cgo painful was from previous experience with it, so I decided to move a Go way.

I considered syscall package as the closest low-level alternative to socket-related functions from libc but stumbled upon some limitations.

syscall.Bind

The syscall.Bind method accepts an abstract sockaddr interface which should implement a private Sockaddr.sockaddr method to return raw pointer to a struct and struct size.

As Sockaddr.sockaddr interface cannot be implemented outside of syscall package, currently it's impossible to use this function for vendor-specific sockets.
I believe that this is an artificial constraint because I was able to use an inner private syscall.bind method with some hacks for vSockets socket:

//go:linkname syscallBind syscall.bind
func syscallBind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error)

afVmci, _ := VMCISock_GetAFValue()
sockFd, _ := syscall.Socket(afVmci, syscall.SOCK_STREAM, 0)
addr := newSockAddr(saFamily(afVmci), uint32(port), VMAddrCIDAny)
addrPtr, ptrSize := addr.sockaddr()

// call to unexported private func
if err := syscallBind(sockFd, addrPtr, ptrSize); err != nil {
    panic(err)
}

if err := syscall.Listen(sockFd, listenBacklogSize); err != nil {
    panic(err)
}

syscall.Accept

Unlike the previous method, syscall.Accept method is more close and only accepts a single parameter - socket file descriptor.
That means, it's impossible to use it for custom sockets (unlike accept() function from libc`)

I tried to take a look how it's implemented in net package and seems like the package uses internal/poll/FD.Accept structure method.

Proposed Actions

I kindly ask the Go contributors and Go team to review my proposal or consider (or recommend) a better solution.

Solution 1

  • Make syscall.Sockaddr.sockaddr method public to make possible implementing it for different sockets.
  • Add alternative syscall.Accept-like method that also accepts custom sockaddr struct (something like FD.accept described above).

Solution 2

Extend net package to make it able to work with custom sockets.
Currently all low-level socket operations are bound to a poll.FD god object-like structure

Thank you.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    • Status
      Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions