Get syscall.Handle from a Go *net.UDPConn on Windows?
go, multicast, networking, sockets, windows
Solution
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:
- implement `dup()` for Windows.
- submit to Go as a changeset
- 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
}
Problem
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