123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- package winio
-
- import (
- "fmt"
- "io"
- "net"
- "os"
- "syscall"
- "time"
- "unsafe"
-
- "github.com/Microsoft/go-winio/pkg/guid"
- )
-
- //sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
-
- const (
- afHvSock = 34 // AF_HYPERV
-
- socketError = ^uintptr(0)
- )
-
- // An HvsockAddr is an address for a AF_HYPERV socket.
- type HvsockAddr struct {
- VMID guid.GUID
- ServiceID guid.GUID
- }
-
- type rawHvsockAddr struct {
- Family uint16
- _ uint16
- VMID guid.GUID
- ServiceID guid.GUID
- }
-
- // Network returns the address's network name, "hvsock".
- func (addr *HvsockAddr) Network() string {
- return "hvsock"
- }
-
- func (addr *HvsockAddr) String() string {
- return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID)
- }
-
- // VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
- func VsockServiceID(port uint32) guid.GUID {
- g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
- g.Data1 = port
- return g
- }
-
- func (addr *HvsockAddr) raw() rawHvsockAddr {
- return rawHvsockAddr{
- Family: afHvSock,
- VMID: addr.VMID,
- ServiceID: addr.ServiceID,
- }
- }
-
- func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
- addr.VMID = raw.VMID
- addr.ServiceID = raw.ServiceID
- }
-
- // HvsockListener is a socket listener for the AF_HYPERV address family.
- type HvsockListener struct {
- sock *win32File
- addr HvsockAddr
- }
-
- // HvsockConn is a connected socket of the AF_HYPERV address family.
- type HvsockConn struct {
- sock *win32File
- local, remote HvsockAddr
- }
-
- func newHvSocket() (*win32File, error) {
- fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
- if err != nil {
- return nil, os.NewSyscallError("socket", err)
- }
- f, err := makeWin32File(fd)
- if err != nil {
- syscall.Close(fd)
- return nil, err
- }
- f.socket = true
- return f, nil
- }
-
- // ListenHvsock listens for connections on the specified hvsock address.
- func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
- l := &HvsockListener{addr: *addr}
- sock, err := newHvSocket()
- if err != nil {
- return nil, l.opErr("listen", err)
- }
- sa := addr.raw()
- err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
- if err != nil {
- return nil, l.opErr("listen", os.NewSyscallError("socket", err))
- }
- err = syscall.Listen(sock.handle, 16)
- if err != nil {
- return nil, l.opErr("listen", os.NewSyscallError("listen", err))
- }
- return &HvsockListener{sock: sock, addr: *addr}, nil
- }
-
- func (l *HvsockListener) opErr(op string, err error) error {
- return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err}
- }
-
- // Addr returns the listener's network address.
- func (l *HvsockListener) Addr() net.Addr {
- return &l.addr
- }
-
- // Accept waits for the next connection and returns it.
- func (l *HvsockListener) Accept() (_ net.Conn, err error) {
- sock, err := newHvSocket()
- if err != nil {
- return nil, l.opErr("accept", err)
- }
- defer func() {
- if sock != nil {
- sock.Close()
- }
- }()
- c, err := l.sock.prepareIo()
- if err != nil {
- return nil, l.opErr("accept", err)
- }
- defer l.sock.wg.Done()
-
- // AcceptEx, per documentation, requires an extra 16 bytes per address.
- const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
- var addrbuf [addrlen * 2]byte
-
- var bytes uint32
- err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
- _, err = l.sock.asyncIo(c, nil, bytes, err)
- if err != nil {
- return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
- }
- conn := &HvsockConn{
- sock: sock,
- }
- conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
- conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
- sock = nil
- return conn, nil
- }
-
- // Close closes the listener, causing any pending Accept calls to fail.
- func (l *HvsockListener) Close() error {
- return l.sock.Close()
- }
-
- /* Need to finish ConnectEx handling
- func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
- sock, err := newHvSocket()
- if err != nil {
- return nil, err
- }
- defer func() {
- if sock != nil {
- sock.Close()
- }
- }()
- c, err := sock.prepareIo()
- if err != nil {
- return nil, err
- }
- defer sock.wg.Done()
- var bytes uint32
- err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
- _, err = sock.asyncIo(ctx, c, nil, bytes, err)
- if err != nil {
- return nil, err
- }
- conn := &HvsockConn{
- sock: sock,
- remote: *addr,
- }
- sock = nil
- return conn, nil
- }
- */
-
- func (conn *HvsockConn) opErr(op string, err error) error {
- return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
- }
-
- func (conn *HvsockConn) Read(b []byte) (int, error) {
- c, err := conn.sock.prepareIo()
- if err != nil {
- return 0, conn.opErr("read", err)
- }
- defer conn.sock.wg.Done()
- buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
- var flags, bytes uint32
- err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
- n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
- if err != nil {
- if _, ok := err.(syscall.Errno); ok {
- err = os.NewSyscallError("wsarecv", err)
- }
- return 0, conn.opErr("read", err)
- } else if n == 0 {
- err = io.EOF
- }
- return n, err
- }
-
- func (conn *HvsockConn) Write(b []byte) (int, error) {
- t := 0
- for len(b) != 0 {
- n, err := conn.write(b)
- if err != nil {
- return t + n, err
- }
- t += n
- b = b[n:]
- }
- return t, nil
- }
-
- func (conn *HvsockConn) write(b []byte) (int, error) {
- c, err := conn.sock.prepareIo()
- if err != nil {
- return 0, conn.opErr("write", err)
- }
- defer conn.sock.wg.Done()
- buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
- var bytes uint32
- err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
- n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
- if err != nil {
- if _, ok := err.(syscall.Errno); ok {
- err = os.NewSyscallError("wsasend", err)
- }
- return 0, conn.opErr("write", err)
- }
- return n, err
- }
-
- // Close closes the socket connection, failing any pending read or write calls.
- func (conn *HvsockConn) Close() error {
- return conn.sock.Close()
- }
-
- func (conn *HvsockConn) shutdown(how int) error {
- err := syscall.Shutdown(conn.sock.handle, syscall.SHUT_RD)
- if err != nil {
- return os.NewSyscallError("shutdown", err)
- }
- return nil
- }
-
- // CloseRead shuts down the read end of the socket.
- func (conn *HvsockConn) CloseRead() error {
- err := conn.shutdown(syscall.SHUT_RD)
- if err != nil {
- return conn.opErr("close", err)
- }
- return nil
- }
-
- // CloseWrite shuts down the write end of the socket, notifying the other endpoint that
- // no more data will be written.
- func (conn *HvsockConn) CloseWrite() error {
- err := conn.shutdown(syscall.SHUT_WR)
- if err != nil {
- return conn.opErr("close", err)
- }
- return nil
- }
-
- // LocalAddr returns the local address of the connection.
- func (conn *HvsockConn) LocalAddr() net.Addr {
- return &conn.local
- }
-
- // RemoteAddr returns the remote address of the connection.
- func (conn *HvsockConn) RemoteAddr() net.Addr {
- return &conn.remote
- }
-
- // SetDeadline implements the net.Conn SetDeadline method.
- func (conn *HvsockConn) SetDeadline(t time.Time) error {
- conn.SetReadDeadline(t)
- conn.SetWriteDeadline(t)
- return nil
- }
-
- // SetReadDeadline implements the net.Conn SetReadDeadline method.
- func (conn *HvsockConn) SetReadDeadline(t time.Time) error {
- return conn.sock.SetReadDeadline(t)
- }
-
- // SetWriteDeadline implements the net.Conn SetWriteDeadline method.
- func (conn *HvsockConn) SetWriteDeadline(t time.Time) error {
- return conn.sock.SetWriteDeadline(t)
- }
|