Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get syscall.Handle from a Go *net.UDPConn on Windows?

How do I obtain the underlying syscall.Handle for a *net.UDPConn on Windows? I want this handle to set the IP_MULTICAST_TTL via syscall.SetsockoptInt. On Linux I do the following:

func setTTL(conn *net.UDPConn, ttl int) error {
    f, err := conn.File()
    if err != nil {
        return err
    }
    defer f.Close()
    fd := int(f.Fd())
    return syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_MULTICAST_TTL, ttl)
}

But on Windows, the implicit dup inside *net.UDPConn's File() fails with:

04:24:49 main.go:150: dup: not supported by windows

And in the source code is marked as a to-do. How can I get this handle? Is there some other way to set the TTL if not?

Update0

I've submitted the shortcomings to the Go issue tracker:

  • SetTTL for *net.UDPConn
  • Implement dup for netFD on Windows
like image 664
Matt Joiner Avatar asked Jul 03 '12 20:07

Matt Joiner


1 Answers

The short answer is impossible. But since that isn't an answer you want to hear, I will give you the right way and wrong way to solve the problem.

The right way:

  1. implement dup() for Windows.
  2. submit to Go as a changeset
  3. wait for it to be released to use it

Obviously the right way has some issues... but I highly recommend doing it. Go needs windows developers to fix up these types of serious problems. The only reason this can't be done in Windows is no one implemented the function

The wrong way:

Until the patch you write gets accepted and released, you can fake it through unsafe. The way the following code works by mirroring the exact structure of a net.UDPConn. This included copying over all structs from net that make up a UDPConn. Then unsafe is used to assert that the local UDPConn is the same as net's UDPConn. The compiler can not check this and takes your word for it. Were the internals of net to ever change, it would compile but god knows what it would do.

All code is untested.

package reallyunsafenet

import (
        "net"
        "sync"
        "syscall"
        "unsafe"
)

// copied from go/src/pkg/net/fd_windows.go
type ioResult struct {
        qty uint32
        err error
}

// copied from go/src/pkg/net/fd_windows.go
type netFD struct {
        // locking/lifetime of sysfd
        sysmu   sync.Mutex
        sysref  int
        closing bool

        // immutable until Close
        sysfd       syscall.Handle
        family      int
        sotype      int
        isConnected bool
        net         string
        laddr       net.Addr
        raddr       net.Addr
        resultc     [2]chan ioResult
        errnoc      [2]chan error

        // owned by client
        rdeadline int64
        rio       sync.Mutex
        wdeadline int64
        wio       sync.Mutex
}

// copied from go/src/pkg/net/udpsock_posix.go
type UDPConn struct {
    fd *netFD
}

// function to get fd
func GetFD(conn *net.UDPConn) syscall.Handle {
        c := (*UDPConn)(unsafe.Pointer(conn))
        return c.fd.sysfd
}
like image 87
Stephen Weinberg Avatar answered Oct 23 '22 03:10

Stephen Weinberg