Repository: go
Issue: proposal: x/sys: permit custom socket implementations
Labels: Proposal

## Brief intro

Hello.

I'm working on [VmWare vSockets / VMCI](https://vdc-download.vmware.com/vmwb-repository/dcr-public/a49be05e-fa6d-4da1-9186-922fbfef149e/a65f3c51-aaeb-476d-80c3-827b805c2f9e/ws9_esx60_vmci_sockets.pdf) 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` ](https://github.com/vmware/open-vm-tools/blob/master/open-vm-tools/lib/include/vmci_sockets.h#L506) 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`](https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go#L876) method accepts an abstract sockaddr interface which should implement a private [`Sockaddr.sockaddr`](https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go#L738) method to return raw pointer to a struct and struct size.

As [`Sockaddr.sockaddr`](https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go#L738) 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
//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`](https://github.com/golang/go/blob/master/src/internal/poll/fd_windows.go#L962) 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`](https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go#L738) 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](https://en.wikipedia.org/wiki/God_object)-like structure

Thank you.