package win32api import ( "bytes" "fmt" "syscall" "unsafe" ) func makeWord(low, high byte) WORD { return WORD(uint16(low) | uint16(high)<<8) } func WSAStartup(versionRequested WORD, data *WSADATA) error { proc, err := getProcAddr("ws2_32.dll", "WSAStartup") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 2, uintptr(versionRequested), uintptr(unsafe.Pointer(data)), 0) if r != 0 { return syscall.Errno(r) } return nil } func WSACleanup() error { proc, err := getProcAddr("ws2_32.dll", "WSACleanup") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 0, 0, 0, 0) if int32(r) == -1 { last := WSAGetLastError() if last != 0 { return syscall.Errno(last) } return syscall.EINVAL } return nil } func WSAGetLastError() int { proc, err := getProcAddr("ws2_32.dll", "WSAGetLastError") if err != nil { return 0 } r, _, _ := syscall.Syscall(proc, 0, 0, 0, 0) return int(int32(r)) } func wsaLastErrorOr(defaultErr error) error { last := WSAGetLastError() if last != 0 { return syscall.Errno(last) } if defaultErr != nil { return defaultErr } return syscall.EINVAL } func GetHostName() (string, error) { var data WSADATA if err := WSAStartup(makeWord(2, 2), &data); err != nil { return "", err } defer func() { _ = WSACleanup() }() proc, err := getProcAddr("ws2_32.dll", "gethostname") if err != nil { return "", err } buf := make([]byte, 256) r, _, _ := syscall.Syscall(proc, 2, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0) if int32(r) == -1 { last := WSAGetLastError() if last != 0 { return "", syscall.Errno(last) } return "", syscall.EINVAL } idx := bytes.IndexByte(buf, 0) if idx < 0 { idx = len(buf) } host := string(buf[:idx]) if host == "" { return "", fmt.Errorf("gethostname returned empty host") } return host, nil } func InetPton(family int, ip string) ([]byte, error) { var data WSADATA if err := WSAStartup(makeWord(2, 2), &data); err != nil { return nil, err } defer func() { _ = WSACleanup() }() proc, err := getProcAddr("ws2_32.dll", "InetPtonW") if err != nil { return nil, err } var out []byte switch family { case AF_INET: out = make([]byte, 4) case AF_INET6: out = make([]byte, 16) default: return nil, fmt.Errorf("unsupported address family: %d", family) } r, _, _ := syscall.Syscall(proc, 3, uintptr(family), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(ip))), uintptr(unsafe.Pointer(&out[0])), ) if int32(r) == 1 { return out, nil } if int32(r) == 0 { return nil, fmt.Errorf("invalid ip address: %s", ip) } last := WSAGetLastError() if last != 0 { return nil, syscall.Errno(last) } return nil, syscall.EINVAL } func InetNtop(family int, addr []byte) (string, error) { var data WSADATA if err := WSAStartup(makeWord(2, 2), &data); err != nil { return "", err } defer func() { _ = WSACleanup() }() switch family { case AF_INET: if len(addr) != 4 { return "", fmt.Errorf("inet4 requires 4 bytes, got %d", len(addr)) } case AF_INET6: if len(addr) != 16 { return "", fmt.Errorf("inet6 requires 16 bytes, got %d", len(addr)) } default: return "", fmt.Errorf("unsupported address family: %d", family) } proc, err := getProcAddr("ws2_32.dll", "InetNtopW") if err != nil { return "", err } buf := make([]uint16, 65) r, _, _ := syscall.Syscall6(proc, 4, uintptr(family), uintptr(unsafe.Pointer(&addr[0])), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0, 0, ) if r == 0 { last := WSAGetLastError() if last != 0 { return "", syscall.Errno(last) } return "", syscall.EINVAL } return syscall.UTF16ToString(buf), nil } func Socket(family, socketType, protocol int32) (SOCKET, error) { proc, err := getProcAddr("ws2_32.dll", "socket") if err != nil { return INVALID_SOCKET, err } r, _, _ := syscall.Syscall(proc, 3, uintptr(family), uintptr(socketType), uintptr(protocol)) s := SOCKET(r) if s == INVALID_SOCKET { return INVALID_SOCKET, wsaLastErrorOr(syscall.EINVAL) } return s, nil } func Closesocket(s SOCKET) error { proc, err := getProcAddr("ws2_32.dll", "closesocket") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 1, uintptr(s), 0, 0) if int32(r) == SOCKET_ERROR { return wsaLastErrorOr(syscall.EINVAL) } return nil } func Connect(s SOCKET, name *SOCKADDR, namelen int32) error { if name == nil { return fmt.Errorf("sockaddr is nil") } proc, err := getProcAddr("ws2_32.dll", "connect") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 3, uintptr(s), uintptr(unsafe.Pointer(name)), uintptr(namelen)) if int32(r) == SOCKET_ERROR { return wsaLastErrorOr(syscall.EINVAL) } return nil } func Bind(s SOCKET, name *SOCKADDR, namelen int32) error { if name == nil { return fmt.Errorf("sockaddr is nil") } proc, err := getProcAddr("ws2_32.dll", "bind") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 3, uintptr(s), uintptr(unsafe.Pointer(name)), uintptr(namelen)) if int32(r) == SOCKET_ERROR { return wsaLastErrorOr(syscall.EINVAL) } return nil } func Listen(s SOCKET, backlog int32) error { proc, err := getProcAddr("ws2_32.dll", "listen") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 2, uintptr(s), uintptr(backlog), 0) if int32(r) == SOCKET_ERROR { return wsaLastErrorOr(syscall.EINVAL) } return nil } func Accept(s SOCKET, addr *SOCKADDR, addrlen *int32) (SOCKET, error) { proc, err := getProcAddr("ws2_32.dll", "accept") if err != nil { return INVALID_SOCKET, err } var addrPtr uintptr if addr != nil { addrPtr = uintptr(unsafe.Pointer(addr)) } var addrLenPtr uintptr if addrlen != nil { addrLenPtr = uintptr(unsafe.Pointer(addrlen)) } r, _, _ := syscall.Syscall(proc, 3, uintptr(s), addrPtr, addrLenPtr) client := SOCKET(r) if client == INVALID_SOCKET { return INVALID_SOCKET, wsaLastErrorOr(syscall.EINVAL) } return client, nil } func Send(s SOCKET, buf []byte, flags int32) (int, error) { proc, err := getProcAddr("ws2_32.dll", "send") if err != nil { return 0, err } var bufPtr uintptr if len(buf) > 0 { bufPtr = uintptr(unsafe.Pointer(&buf[0])) } r, _, _ := syscall.Syscall6(proc, 4, uintptr(s), bufPtr, uintptr(len(buf)), uintptr(flags), 0, 0) if int32(r) == SOCKET_ERROR { return 0, wsaLastErrorOr(syscall.EINVAL) } return int(r), nil } func Recv(s SOCKET, buf []byte, flags int32) (int, error) { proc, err := getProcAddr("ws2_32.dll", "recv") if err != nil { return 0, err } var bufPtr uintptr if len(buf) > 0 { bufPtr = uintptr(unsafe.Pointer(&buf[0])) } r, _, _ := syscall.Syscall6(proc, 4, uintptr(s), bufPtr, uintptr(len(buf)), uintptr(flags), 0, 0) if int32(r) == SOCKET_ERROR { return 0, wsaLastErrorOr(syscall.EINVAL) } return int(r), nil } func Shutdown(s SOCKET, how int32) error { proc, err := getProcAddr("ws2_32.dll", "shutdown") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 2, uintptr(s), uintptr(how), 0) if int32(r) == SOCKET_ERROR { return wsaLastErrorOr(syscall.EINVAL) } return nil } func GetSockName(s SOCKET, name *SOCKADDR, nameLen *int32) error { if name == nil || nameLen == nil { return syscall.EINVAL } proc, err := getProcAddr("ws2_32.dll", "getsockname") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 3, uintptr(s), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen))) if int32(r) == SOCKET_ERROR { return wsaLastErrorOr(syscall.EINVAL) } return nil } func GetPeerName(s SOCKET, name *SOCKADDR, nameLen *int32) error { if name == nil || nameLen == nil { return syscall.EINVAL } proc, err := getProcAddr("ws2_32.dll", "getpeername") if err != nil { return err } r, _, _ := syscall.Syscall(proc, 3, uintptr(s), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen))) if int32(r) == SOCKET_ERROR { return wsaLastErrorOr(syscall.EINVAL) } return nil } func SetSockOpt(s SOCKET, level, optName int32, optValue []byte) error { proc, err := getProcAddr("ws2_32.dll", "setsockopt") if err != nil { return err } var valuePtr uintptr if len(optValue) > 0 { valuePtr = uintptr(unsafe.Pointer(&optValue[0])) } r, _, _ := syscall.Syscall6(proc, 5, uintptr(s), uintptr(level), uintptr(optName), valuePtr, uintptr(len(optValue)), 0, ) if int32(r) == SOCKET_ERROR { return wsaLastErrorOr(syscall.EINVAL) } return nil } func GetSockOpt(s SOCKET, level, optName int32, optValue []byte) (int32, error) { proc, err := getProcAddr("ws2_32.dll", "getsockopt") if err != nil { return 0, err } var valuePtr uintptr if len(optValue) > 0 { valuePtr = uintptr(unsafe.Pointer(&optValue[0])) } optLen := int32(len(optValue)) r, _, _ := syscall.Syscall6(proc, 5, uintptr(s), uintptr(level), uintptr(optName), valuePtr, uintptr(unsafe.Pointer(&optLen)), 0, ) if int32(r) == SOCKET_ERROR { return 0, wsaLastErrorOr(syscall.EINVAL) } return optLen, nil } func SetSockOptInt(s SOCKET, level, optName int32, value int32) error { buf := (*[4]byte)(unsafe.Pointer(&value))[:] return SetSockOpt(s, level, optName, buf) } func GetSockOptInt(s SOCKET, level, optName int32) (int32, error) { var value int32 buf := (*[4]byte)(unsafe.Pointer(&value))[:] optLen, err := GetSockOpt(s, level, optName, buf) if err != nil { return 0, err } if optLen < 4 { return 0, fmt.Errorf("getsockopt returned short length: %d", optLen) } return value, nil } func SendTo(s SOCKET, buf []byte, flags int32, to *SOCKADDR, toLen int32) (int, error) { proc, err := getProcAddr("ws2_32.dll", "sendto") if err != nil { return 0, err } var bufPtr uintptr if len(buf) > 0 { bufPtr = uintptr(unsafe.Pointer(&buf[0])) } var toPtr uintptr if to != nil { toPtr = uintptr(unsafe.Pointer(to)) } r, _, _ := syscall.Syscall6(proc, 6, uintptr(s), bufPtr, uintptr(len(buf)), uintptr(flags), toPtr, uintptr(toLen), ) if int32(r) == SOCKET_ERROR { return 0, wsaLastErrorOr(syscall.EINVAL) } return int(r), nil } func RecvFrom(s SOCKET, buf []byte, flags int32, from *SOCKADDR, fromLen *int32) (int, error) { proc, err := getProcAddr("ws2_32.dll", "recvfrom") if err != nil { return 0, err } var bufPtr uintptr if len(buf) > 0 { bufPtr = uintptr(unsafe.Pointer(&buf[0])) } var fromPtr uintptr if from != nil { fromPtr = uintptr(unsafe.Pointer(from)) } var fromLenPtr uintptr if fromLen != nil { fromLenPtr = uintptr(unsafe.Pointer(fromLen)) } r, _, _ := syscall.Syscall6(proc, 6, uintptr(s), bufPtr, uintptr(len(buf)), uintptr(flags), fromPtr, fromLenPtr, ) if int32(r) == SOCKET_ERROR { return 0, wsaLastErrorOr(syscall.EINVAL) } return int(r), nil } func GetAddrInfo(node, service string, hints *ADDRINFOW) (*ADDRINFOW, error) { var data WSADATA if err := WSAStartup(makeWord(2, 2), &data); err != nil { return nil, err } defer func() { _ = WSACleanup() }() proc, err := getProcAddr("ws2_32.dll", "GetAddrInfoW") if err != nil { return nil, err } var nodePtr *uint16 if node != "" { nodePtr = syscall.StringToUTF16Ptr(node) } var servicePtr *uint16 if service != "" { servicePtr = syscall.StringToUTF16Ptr(service) } var result *ADDRINFOW r, _, _ := syscall.Syscall6(proc, 4, uintptr(unsafe.Pointer(nodePtr)), uintptr(unsafe.Pointer(servicePtr)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(&result)), 0, 0, ) if int32(r) != 0 { return nil, fmt.Errorf("GetAddrInfoW failed: %d", int32(r)) } if result == nil { return nil, fmt.Errorf("GetAddrInfoW returned nil result") } return result, nil } func FreeAddrInfo(result *ADDRINFOW) error { if result == nil { return nil } proc, err := getProcAddr("ws2_32.dll", "FreeAddrInfoW") if err != nil { return err } syscall.Syscall(proc, 1, uintptr(unsafe.Pointer(result)), 0, 0) return nil } func GetNameInfo(sa *SOCKADDR, saLen int32, flags int32) (string, string, error) { if sa == nil { return "", "", fmt.Errorf("sockaddr is nil") } var data WSADATA if err := WSAStartup(makeWord(2, 2), &data); err != nil { return "", "", err } defer func() { _ = WSACleanup() }() proc, err := getProcAddr("ws2_32.dll", "GetNameInfoW") if err != nil { return "", "", err } host := make([]uint16, NI_MAXHOST) service := make([]uint16, NI_MAXSERV) r, _, _ := syscall.Syscall9(proc, 7, uintptr(unsafe.Pointer(sa)), uintptr(saLen), uintptr(unsafe.Pointer(&host[0])), uintptr(len(host)), uintptr(unsafe.Pointer(&service[0])), uintptr(len(service)), uintptr(flags), 0, 0, ) if int32(r) != 0 { return "", "", fmt.Errorf("GetNameInfoW failed: %d", int32(r)) } return syscall.UTF16ToString(host), syscall.UTF16ToString(service), nil } func SockaddrIPString(sa *SOCKADDR) (string, error) { if sa == nil { return "", fmt.Errorf("sockaddr is nil") } switch int(sa.Family) { case AF_INET: addr := (*SOCKADDR_IN)(unsafe.Pointer(sa)) return InetNtop(AF_INET, addr.Addr[:]) case AF_INET6: addr := (*SOCKADDR_IN6)(unsafe.Pointer(sa)) return InetNtop(AF_INET6, addr.Addr[:]) default: return "", fmt.Errorf("unsupported sockaddr family: %d", sa.Family) } } func Htons(v uint16) uint16 { return (v << 8) | (v >> 8) } func Ntohs(v uint16) uint16 { return Htons(v) } func htons(v uint16) uint16 { return Htons(v) }