win32api/ws2_32.go

592 lines
13 KiB
Go
Raw Permalink Normal View History

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)
}