123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- //go:build windows
- package yu_sys
- import (
- yu_strconv "gogs.qqck.cn/s/tools/strconv"
- "net"
- "net/netip"
- "syscall"
- "unsafe"
- )
- //go:cgo_import_dynamic WSAStartup WSAStartup "ws2_32.dll"
- //go:linkname WSAStartup WSAStartup
- var WSAStartup Address
- //go:cgo_import_dynamic socket socket "ws2_32.dll"
- //go:linkname Socket socket
- var Socket Address
- //go:cgo_import_dynamic ioctlsocket ioctlsocket "ws2_32.dll"
- //go:linkname Ioctlsocket ioctlsocket
- var Ioctlsocket Address
- //go:cgo_import_dynamic connect connect "ws2_32.dll"
- //go:linkname Connect connect
- var Connect Address
- //go:cgo_import_dynamic select select "ws2_32.dll"
- //go:linkname Select select
- var Select Address
- //go:cgo_import_dynamic send send "ws2_32.dll"
- //go:linkname Send send
- var Send Address
- //go:cgo_import_dynamic recv recv "ws2_32.dll"
- //go:linkname Recv recv
- var Recv Address
- //go:cgo_import_dynamic closesocket closesocket "ws2_32.dll"
- //go:linkname Closesocket closesocket
- var Closesocket Address
- func init() {
- var j_wsadata syscall.WSAData
- WSAStartup.Call(0x02_02, unsafe.Pointer(&j_wsadata)) // 调用方可以使用的最高版本的 Windows 套接字规范。 高序字节指定次要版本号;低序字节指定主版本号。
- }
- const (
- AF_UNSPEC = 0 // 地址系列未指定。
- AF_INET = 2 // Internet 协议版本 4 (IPv4) 地址系列。
- AF_IPX = 6 // IPX/SPX 地址系列。 仅当安装了 NWLink IPX/SPX NetBIOS 兼容传输协议时,才支持此地址系列。Windows Vista 及更高版本不支持此地址系列。
- AF_APPLETALK = 16 // AppleTalk 地址系列。 仅当安装了 AppleTalk 协议时,才支持此地址系列。Windows Vista 及更高版本不支持此地址系列。
- AF_NETBIOS = 17 // NetBIOS 地址系列。 仅当安装了适用于 NetBIOS 的 Windows 套接字提供程序时,才支持此地址系列。32 位版本的 Windows 支持 NetBIOS 的 Windows 套接字提供程序。 默认情况下,此提供程序安装在 32 位版本的 Windows 上。64 位版本的 Windows 不支持 NetBIOS 的 Windows 套接字提供程序,包括 Windows 7、Windows Server 2008、Windows Vista、Windows Server 2003 或 Windows XP。适用于 NetBIOS 的 Windows 套接字提供程序仅支持 类型 参数设置为 SOCK_DGRAM的套接字。适用于 NetBIOS 的 Windows 套接字提供程序与 NetBIOS 编程接口不直接相关。 Windows Vista、Windows Server 2008 及更高版本不支持 NetBIOS 编程接口。
- AF_INET6 = 23 // Internet 协议版本 6 (IPv6) 地址系列。
- AF_IRDA = 26 // IrDA (IrDA) 地址系列。仅当计算机安装了红外端口和驱动程序时,才支持此地址系列。
- AF_BTH = 32 // 蓝牙地址系列。如果计算机安装了蓝牙适配器和驱动程序,则 SP2 或更高版本的 Windows XP 支持此地址系列。
- )
- const (
- SOCK_STREAM = 1 // 一种套接字类型,它通过 OOB 数据传输机制提供排序的、可靠的双向、基于连接的字节流。 此套接字类型对 Internet 地址系列 (AF_INET 或 AF_INET6) 使用传输控制协议 (TCP) 。
- SOCK_DGRAM = 2 // 支持数据报的套接字类型,这些数据报是固定 (通常较小) 最大长度的无连接、不可靠的缓冲区。 此套接字类型对 Internet 地址系列 (AF_INET 或 AF_INET6) 使用用户数据报协议 (UDP) 。
- SOCK_RAW = 3 // 一种套接字类型,它提供允许应用程序操作下一层协议标头的原始套接字。 若要操作 IPv4 标头,必须在套接字上设置 IP_HDRINCL 套接字选项。 若要操作 IPv6 标头,必须在套接字上设置 IPV6_HDRINCL 套接字选项。
- SOCK_RDM = 4 // 提供可靠消息数据报的套接字类型。 此类型的一个示例是 Windows 中的实用常规多播 (PGM) 多播协议实现,通常称为 可靠多播编程。 仅当安装了可靠多播协议时,才支持此 类型 值。
- SOCK_SEQPACKET = 5 // 提供基于数据报的伪流数据包的套接字类型。
- )
- const (
- IPPROTO_ICMP = 1 // Internet 控制消息协议 (ICMP) 。 当 af 参数 AF_UNSPEC、 AF_INET或 AF_INET6 且 类型 参数 SOCK_RAW 或未指定时,此值可能为。 Windows XP 及更高版本支持此 协议 值。
- IPPROTO_IGMP = 2 // Internet 组管理协议 (IGMP) 。 当 af 参数 AF_UNSPEC、 AF_INET或 AF_INET6 且 类型 参数 SOCK_RAW 或未指定时,此值可能为 。Windows XP 及更高版本支持此 协议 值。
- BTHPROTO_RFCOMM = 3 // 蓝牙射频通信 (蓝牙 RFCOMM) 协议。 当 af 参数 AF_BTH 且类型参数 SOCK_STREAM 时,这是一个可能的值。 具有 SP2 或更高版本的 Windows XP 支持此 协议 值。
- IPPROTO_TCP = 6 // 传输控制协议 (TCP) 。 当 af 参数 AF_INET 或 AF_INET6 且类型参数 SOCK_STREAM 时,这是一个可能的值。
- IPPROTO_UDP = 17 // 用户数据报协议 (UDP) 。 当 af 参数 AF_INET 或 AF_INET6 且类型参数 SOCK_DGRAM 时,这是一个可能的值。
- IPPROTO_ICMPV6 = 58 // Internet 控制消息协议版本 6 (ICMPv6) 。 当 af 参数 AF_UNSPEC、 AF_INET 或 AF_INET6 且 类型 参数 SOCK_RAW 或未指定时,此值可能为 。Windows XP 及更高版本支持此 协议 值。
- IPPROTO_RM = 113 // 可靠多播的 PGM 协议。 当 af 参数 AF_INET 且类型参数 SOCK_RDM 时,这是一个可能的值。 在 Windows Vista 及更高版本发布的Windows SDK中,此协议也称为IPPROTO_PGM。仅当安装了可靠多播 协议 时,才支持此协议值。
- )
- const INVALID_SOCKET = 0
- const FIONBIO = 2147772030 // 在 套接字上启用或禁用非阻止模式。 lpvInBuffer 参数指向一个无符号长 (QoS) ,如果要启用非阻止模式,则为非零;如果要禁用该模式,则为零。 创建套接字时,它将在阻止模式下运行 (即) 禁用非阻止模式。 这与 BSD 套接字一致。WSAAsyncSelect 或 WSAEventSelect 例程自动将套接字设置为非阻止模式。 如果已在套接字上发出 WSAAsyncSelect 或 WSAEventSelect ,则使用 WSAIoctl 将套接字重新设置为阻止模式的任何尝试都将失败,WSAEINVAL 会失败。 若要将套接字重新设置为阻止模式,应用程序必须首先通过调用 lEvent 参数等于零的 WSAAsyncSelect 来禁用 WSAAsyncSelect,或者通过调用 WSAEventSelect(lNetworkEvents 参数等于零)来禁用 WSAEventSelect。
- const SOCKET_ERROR = -1
- type Sockaddr interface {
- Sockaddr() (ptr unsafe.Pointer, len uintptr)
- }
- type Sockaddr_in struct {
- Family uint16
- Port uint16
- Addr [4]byte /* in_addr */
- Zero [8]uint8
- }
- func (sa *Sockaddr_in) Sockaddr() (unsafe.Pointer, uintptr) {
- return unsafe.Pointer(sa), unsafe.Sizeof(*sa)
- }
- type Sockaddr_in6 struct {
- Family uint16
- Port uint16
- Flowinfo uint32
- Addr [16]byte /* in6_addr */
- Scope_id uint32
- }
- func (sa *Sockaddr_in6) Sockaddr() (unsafe.Pointer, uintptr) {
- return unsafe.Pointer(sa), unsafe.Sizeof(*sa)
- }
- type FDSET struct {
- Count uintptr
- Fds uintptr // []uintptr
- }
- type TIMEVAL struct {
- TvSec int32
- TvUsec int32
- }
- func Socket_connect(host string, port int, sec, usec int32) uintptr {
- var j_addr netip.Addr
- var j_err error
- if j_addr, j_err = netip.ParseAddr(host); j_err != nil {
- j_addrs, j_err := net.LookupHost(host)
- if j_err != nil || len(j_addrs) == 0 {
- return INVALID_SOCKET
- }
- if j_addr, j_err = netip.ParseAddr(j_addrs[0]); j_err != nil {
- return INVALID_SOCKET
- }
- }
- j_fd := uintptr(INVALID_SOCKET)
- if j_addr.Is4() {
- if j_fd = Socket.CallUintptr(AF_INET, SOCK_STREAM, IPPROTO_TCP); j_fd == INVALID_SOCKET {
- return INVALID_SOCKET
- }
- } else if j_addr.Is6() {
- if j_fd = Socket.CallUintptr(AF_INET6, SOCK_STREAM, IPPROTO_TCP); j_fd == INVALID_SOCKET {
- return INVALID_SOCKET
- }
- } else {
- return INVALID_SOCKET
- }
- var j_sockaddr Sockaddr
- if j_addr.Is4() {
- j_sockaddr = &Sockaddr_in{
- Family: AF_INET,
- Port: uint16(port)>>8 | uint16(port)<<8,
- Addr: j_addr.As4(),
- }
- } else if j_addr.Is6() {
- j_sockaddr = &Sockaddr_in6{
- Family: AF_INET6,
- Port: uint16(port)>>8 | uint16(port)<<8,
- Addr: j_addr.As16(),
- Scope_id: yu_strconv.ParseUint32(j_addr.Zone()),
- }
- }
- j_argp := 1
- if Ioctlsocket.CallInt32(j_fd, FIONBIO, &j_argp) == SOCKET_ERROR {
- Closesocket.Call(j_fd)
- return INVALID_SOCKET
- }
- j_sec, j_usec := sec, usec
- const j_timeout = 1000 * 100
- _connect:
- j_sockaddr_ptr, j_sockaddr_len := j_sockaddr.Sockaddr()
- if j_ok := Connect.CallInt32(j_fd, j_sockaddr_ptr, j_sockaddr_len); j_ok != SOCKET_ERROR && j_ok != 0 {
- Closesocket.Call(j_fd)
- return INVALID_SOCKET
- }
- if !Socket_is_write(j_fd, 0, j_timeout) {
- if j_usec > 0 {
- j_usec -= j_timeout
- goto _connect
- } else if j_sec > 0 {
- j_sec--
- j_usec = 1000 * 1000
- j_usec -= j_timeout
- goto _connect
- }
- Closesocket.Call(j_fd)
- return INVALID_SOCKET
- }
- j_argp = 0
- if Ioctlsocket.CallInt32(j_fd, FIONBIO, &j_argp) == SOCKET_ERROR {
- Closesocket.Call(j_fd)
- return INVALID_SOCKET
- }
- return j_fd
- }
- func Socket_is_write(fd uintptr, sec, usec int32) bool {
- switch Select.CallInt32(0, 0, unsafe.Pointer(&FDSET{1, fd}), 0, unsafe.Pointer(&TIMEVAL{sec, usec})) {
- case -1:
- return false // ErrClose
- case 0:
- return false // ErrTimeout
- case 1:
- return true
- default:
- return false // ErrNot
- }
- }
- func Socket_is_read(fd uintptr, sec, usec int32) bool {
- switch Select.CallInt32(0, unsafe.Pointer(&FDSET{1, fd}), 0, 0, unsafe.Pointer(&TIMEVAL{sec, usec})) {
- case -1:
- return false // ErrClose
- case 0:
- return false // ErrTimeout
- case 1:
- return true
- default:
- return false // ErrNot
- }
- }
- const _send_size_max = 1024 * 1024 * 32 // 32 MB
- func Socket_write_tcp(fd uintptr, buf []byte, sec, usec int32) bool {
- if fd == INVALID_SOCKET {
- return false
- }
- if len(buf) == 0 {
- return true
- }
- j_buf_ptr, j_buf_len, j_move := uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), uintptr(0)
- for j_buf_len > 0 {
- if !Socket_is_write(fd, sec, usec) {
- return false
- }
- if j_buf_len > _send_size_max {
- j_move, _, _ = Send.Call(fd, j_buf_ptr, _send_size_max, 0)
- } else {
- j_move, _, _ = Send.Call(fd, j_buf_ptr, j_buf_len, 0)
- }
- if int32(j_move) < 0 {
- return false
- }
- j_buf_ptr += j_move
- j_buf_len -= j_move
- }
- return true
- }
- func Socket_read_tcp(fd uintptr, size int, sec, usec int32) []byte {
- if fd == INVALID_SOCKET {
- return nil
- }
- if size < 1 {
- return nil
- }
- if !Socket_is_read(fd, sec, usec) {
- return nil
- }
- j_buf := make([]byte, size)
- j_size, _, _ := Recv.Call(fd, j_buf, len(j_buf), 0)
- if int32(j_size) < 1 {
- return nil
- }
- j_buf = j_buf[:j_size]
- return j_buf
- }
|