windows_ws2_32.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. //go:build windows
  2. package yu_sys
  3. import (
  4. yu_strconv "gogs.qqck.cn/s/tools/strconv"
  5. "net"
  6. "net/netip"
  7. "syscall"
  8. "unsafe"
  9. )
  10. //go:cgo_import_dynamic WSAStartup WSAStartup "ws2_32.dll"
  11. //go:linkname WSAStartup WSAStartup
  12. var WSAStartup Address
  13. //go:cgo_import_dynamic socket socket "ws2_32.dll"
  14. //go:linkname Socket socket
  15. var Socket Address
  16. //go:cgo_import_dynamic ioctlsocket ioctlsocket "ws2_32.dll"
  17. //go:linkname Ioctlsocket ioctlsocket
  18. var Ioctlsocket Address
  19. //go:cgo_import_dynamic connect connect "ws2_32.dll"
  20. //go:linkname Connect connect
  21. var Connect Address
  22. //go:cgo_import_dynamic select select "ws2_32.dll"
  23. //go:linkname Select select
  24. var Select Address
  25. //go:cgo_import_dynamic send send "ws2_32.dll"
  26. //go:linkname Send send
  27. var Send Address
  28. //go:cgo_import_dynamic recv recv "ws2_32.dll"
  29. //go:linkname Recv recv
  30. var Recv Address
  31. //go:cgo_import_dynamic closesocket closesocket "ws2_32.dll"
  32. //go:linkname Closesocket closesocket
  33. var Closesocket Address
  34. func init() {
  35. var j_wsadata syscall.WSAData
  36. WSAStartup.Call(0x02_02, unsafe.Pointer(&j_wsadata)) // 调用方可以使用的最高版本的 Windows 套接字规范。 高序字节指定次要版本号;低序字节指定主版本号。
  37. }
  38. const (
  39. AF_UNSPEC = 0 // 地址系列未指定。
  40. AF_INET = 2 // Internet 协议版本 4 (IPv4) 地址系列。
  41. AF_IPX = 6 // IPX/SPX 地址系列。 仅当安装了 NWLink IPX/SPX NetBIOS 兼容传输协议时,才支持此地址系列。Windows Vista 及更高版本不支持此地址系列。
  42. AF_APPLETALK = 16 // AppleTalk 地址系列。 仅当安装了 AppleTalk 协议时,才支持此地址系列。Windows Vista 及更高版本不支持此地址系列。
  43. 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 编程接口。
  44. AF_INET6 = 23 // Internet 协议版本 6 (IPv6) 地址系列。
  45. AF_IRDA = 26 // IrDA (IrDA) 地址系列。仅当计算机安装了红外端口和驱动程序时,才支持此地址系列。
  46. AF_BTH = 32 // 蓝牙地址系列。如果计算机安装了蓝牙适配器和驱动程序,则 SP2 或更高版本的 Windows XP 支持此地址系列。
  47. )
  48. const (
  49. SOCK_STREAM = 1 // 一种套接字类型,它通过 OOB 数据传输机制提供排序的、可靠的双向、基于连接的字节流。 此套接字类型对 Internet 地址系列 (AF_INET 或 AF_INET6) 使用传输控制协议 (TCP) 。
  50. SOCK_DGRAM = 2 // 支持数据报的套接字类型,这些数据报是固定 (通常较小) 最大长度的无连接、不可靠的缓冲区。 此套接字类型对 Internet 地址系列 (AF_INET 或 AF_INET6) 使用用户数据报协议 (UDP) 。
  51. SOCK_RAW = 3 // 一种套接字类型,它提供允许应用程序操作下一层协议标头的原始套接字。 若要操作 IPv4 标头,必须在套接字上设置 IP_HDRINCL 套接字选项。 若要操作 IPv6 标头,必须在套接字上设置 IPV6_HDRINCL 套接字选项。
  52. SOCK_RDM = 4 // 提供可靠消息数据报的套接字类型。 此类型的一个示例是 Windows 中的实用常规多播 (PGM) 多播协议实现,通常称为 可靠多播编程。 仅当安装了可靠多播协议时,才支持此 类型 值。
  53. SOCK_SEQPACKET = 5 // 提供基于数据报的伪流数据包的套接字类型。
  54. )
  55. const (
  56. IPPROTO_ICMP = 1 // Internet 控制消息协议 (ICMP) 。 当 af 参数 AF_UNSPEC、 AF_INET或 AF_INET6 且 类型 参数 SOCK_RAW 或未指定时,此值可能为。 Windows XP 及更高版本支持此 协议 值。
  57. IPPROTO_IGMP = 2 // Internet 组管理协议 (IGMP) 。 当 af 参数 AF_UNSPEC、 AF_INET或 AF_INET6 且 类型 参数 SOCK_RAW 或未指定时,此值可能为 。Windows XP 及更高版本支持此 协议 值。
  58. BTHPROTO_RFCOMM = 3 // 蓝牙射频通信 (蓝牙 RFCOMM) 协议。 当 af 参数 AF_BTH 且类型参数 SOCK_STREAM 时,这是一个可能的值。 具有 SP2 或更高版本的 Windows XP 支持此 协议 值。
  59. IPPROTO_TCP = 6 // 传输控制协议 (TCP) 。 当 af 参数 AF_INET 或 AF_INET6 且类型参数 SOCK_STREAM 时,这是一个可能的值。
  60. IPPROTO_UDP = 17 // 用户数据报协议 (UDP) 。 当 af 参数 AF_INET 或 AF_INET6 且类型参数 SOCK_DGRAM 时,这是一个可能的值。
  61. IPPROTO_ICMPV6 = 58 // Internet 控制消息协议版本 6 (ICMPv6) 。 当 af 参数 AF_UNSPEC、 AF_INET 或 AF_INET6 且 类型 参数 SOCK_RAW 或未指定时,此值可能为 。Windows XP 及更高版本支持此 协议 值。
  62. IPPROTO_RM = 113 // 可靠多播的 PGM 协议。 当 af 参数 AF_INET 且类型参数 SOCK_RDM 时,这是一个可能的值。 在 Windows Vista 及更高版本发布的Windows SDK中,此协议也称为IPPROTO_PGM。仅当安装了可靠多播 协议 时,才支持此协议值。
  63. )
  64. const INVALID_SOCKET = 0
  65. const FIONBIO = 2147772030 // 在 套接字上启用或禁用非阻止模式。 lpvInBuffer 参数指向一个无符号长 (QoS) ,如果要启用非阻止模式,则为非零;如果要禁用该模式,则为零。 创建套接字时,它将在阻止模式下运行 (即) 禁用非阻止模式。 这与 BSD 套接字一致。WSAAsyncSelect 或 WSAEventSelect 例程自动将套接字设置为非阻止模式。 如果已在套接字上发出 WSAAsyncSelect 或 WSAEventSelect ,则使用 WSAIoctl 将套接字重新设置为阻止模式的任何尝试都将失败,WSAEINVAL 会失败。 若要将套接字重新设置为阻止模式,应用程序必须首先通过调用 lEvent 参数等于零的 WSAAsyncSelect 来禁用 WSAAsyncSelect,或者通过调用 WSAEventSelect(lNetworkEvents 参数等于零)来禁用 WSAEventSelect。
  66. const SOCKET_ERROR = -1
  67. type Sockaddr interface {
  68. Sockaddr() (ptr unsafe.Pointer, len uintptr)
  69. }
  70. type Sockaddr_in struct {
  71. Family uint16
  72. Port uint16
  73. Addr [4]byte /* in_addr */
  74. Zero [8]uint8
  75. }
  76. func (sa *Sockaddr_in) Sockaddr() (unsafe.Pointer, uintptr) {
  77. return unsafe.Pointer(sa), unsafe.Sizeof(*sa)
  78. }
  79. type Sockaddr_in6 struct {
  80. Family uint16
  81. Port uint16
  82. Flowinfo uint32
  83. Addr [16]byte /* in6_addr */
  84. Scope_id uint32
  85. }
  86. func (sa *Sockaddr_in6) Sockaddr() (unsafe.Pointer, uintptr) {
  87. return unsafe.Pointer(sa), unsafe.Sizeof(*sa)
  88. }
  89. type FDSET struct {
  90. Count uintptr
  91. Fds uintptr // []uintptr
  92. }
  93. type TIMEVAL struct {
  94. TvSec int32
  95. TvUsec int32
  96. }
  97. func Socket_connect(host string, port int, sec, usec int32) uintptr {
  98. var j_addr netip.Addr
  99. var j_err error
  100. if j_addr, j_err = netip.ParseAddr(host); j_err != nil {
  101. j_addrs, j_err := net.LookupHost(host)
  102. if j_err != nil || len(j_addrs) == 0 {
  103. return INVALID_SOCKET
  104. }
  105. if j_addr, j_err = netip.ParseAddr(j_addrs[0]); j_err != nil {
  106. return INVALID_SOCKET
  107. }
  108. }
  109. j_fd := uintptr(INVALID_SOCKET)
  110. if j_addr.Is4() {
  111. if j_fd = Socket.CallUintptr(AF_INET, SOCK_STREAM, IPPROTO_TCP); j_fd == INVALID_SOCKET {
  112. return INVALID_SOCKET
  113. }
  114. } else if j_addr.Is6() {
  115. if j_fd = Socket.CallUintptr(AF_INET6, SOCK_STREAM, IPPROTO_TCP); j_fd == INVALID_SOCKET {
  116. return INVALID_SOCKET
  117. }
  118. } else {
  119. return INVALID_SOCKET
  120. }
  121. var j_sockaddr Sockaddr
  122. if j_addr.Is4() {
  123. j_sockaddr = &Sockaddr_in{
  124. Family: AF_INET,
  125. Port: uint16(port)>>8 | uint16(port)<<8,
  126. Addr: j_addr.As4(),
  127. }
  128. } else if j_addr.Is6() {
  129. j_sockaddr = &Sockaddr_in6{
  130. Family: AF_INET6,
  131. Port: uint16(port)>>8 | uint16(port)<<8,
  132. Addr: j_addr.As16(),
  133. Scope_id: yu_strconv.ParseUint32(j_addr.Zone()),
  134. }
  135. }
  136. j_argp := 1
  137. if Ioctlsocket.CallInt32(j_fd, FIONBIO, &j_argp) == SOCKET_ERROR {
  138. Closesocket.Call(j_fd)
  139. return INVALID_SOCKET
  140. }
  141. j_sec, j_usec := sec, usec
  142. const j_timeout = 1000 * 100
  143. _connect:
  144. j_sockaddr_ptr, j_sockaddr_len := j_sockaddr.Sockaddr()
  145. if j_ok := Connect.CallInt32(j_fd, j_sockaddr_ptr, j_sockaddr_len); j_ok != SOCKET_ERROR && j_ok != 0 {
  146. Closesocket.Call(j_fd)
  147. return INVALID_SOCKET
  148. }
  149. if !Socket_is_write(j_fd, 0, j_timeout) {
  150. if j_usec > 0 {
  151. j_usec -= j_timeout
  152. goto _connect
  153. } else if j_sec > 0 {
  154. j_sec--
  155. j_usec = 1000 * 1000
  156. j_usec -= j_timeout
  157. goto _connect
  158. }
  159. Closesocket.Call(j_fd)
  160. return INVALID_SOCKET
  161. }
  162. j_argp = 0
  163. if Ioctlsocket.CallInt32(j_fd, FIONBIO, &j_argp) == SOCKET_ERROR {
  164. Closesocket.Call(j_fd)
  165. return INVALID_SOCKET
  166. }
  167. return j_fd
  168. }
  169. func Socket_is_write(fd uintptr, sec, usec int32) bool {
  170. switch Select.CallInt32(0, 0, unsafe.Pointer(&FDSET{1, fd}), 0, unsafe.Pointer(&TIMEVAL{sec, usec})) {
  171. case -1:
  172. return false // ErrClose
  173. case 0:
  174. return false // ErrTimeout
  175. case 1:
  176. return true
  177. default:
  178. return false // ErrNot
  179. }
  180. }
  181. func Socket_is_read(fd uintptr, sec, usec int32) bool {
  182. switch Select.CallInt32(0, unsafe.Pointer(&FDSET{1, fd}), 0, 0, unsafe.Pointer(&TIMEVAL{sec, usec})) {
  183. case -1:
  184. return false // ErrClose
  185. case 0:
  186. return false // ErrTimeout
  187. case 1:
  188. return true
  189. default:
  190. return false // ErrNot
  191. }
  192. }
  193. const _send_size_max = 1024 * 1024 * 32 // 32 MB
  194. func Socket_write_tcp(fd uintptr, buf []byte, sec, usec int32) bool {
  195. if fd == INVALID_SOCKET {
  196. return false
  197. }
  198. if len(buf) == 0 {
  199. return true
  200. }
  201. j_buf_ptr, j_buf_len, j_move := uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), uintptr(0)
  202. for j_buf_len > 0 {
  203. if !Socket_is_write(fd, sec, usec) {
  204. return false
  205. }
  206. if j_buf_len > _send_size_max {
  207. j_move, _, _ = Send.Call(fd, j_buf_ptr, _send_size_max, 0)
  208. } else {
  209. j_move, _, _ = Send.Call(fd, j_buf_ptr, j_buf_len, 0)
  210. }
  211. if int32(j_move) < 0 {
  212. return false
  213. }
  214. j_buf_ptr += j_move
  215. j_buf_len -= j_move
  216. }
  217. return true
  218. }
  219. func Socket_read_tcp(fd uintptr, size int, sec, usec int32) []byte {
  220. if fd == INVALID_SOCKET {
  221. return nil
  222. }
  223. if size < 1 {
  224. return nil
  225. }
  226. if !Socket_is_read(fd, sec, usec) {
  227. return nil
  228. }
  229. j_buf := make([]byte, size)
  230. j_size, _, _ := Recv.Call(fd, j_buf, len(j_buf), 0)
  231. if int32(j_size) < 1 {
  232. return nil
  233. }
  234. j_buf = j_buf[:j_size]
  235. return j_buf
  236. }