@@ -10,6 +10,7 @@ import (
1010 "errors"
1111 "net"
1212 "net/netip"
13+ "runtime"
1314 "strconv"
1415 "sync"
1516 "syscall"
@@ -22,15 +23,16 @@ var (
2223 _ Bind = (* StdNetBind )(nil )
2324)
2425
25- // StdNetBind implements Bind for all platforms except Windows.
26+ // StdNetBind implements Bind for all platforms. While Windows has its own Bind
27+ // (see bind_windows.go), it may fall back to StdNetBind.
2628type StdNetBind struct {
2729 mu sync.Mutex // protects following fields
2830 ipv4 * net.UDPConn
2931 ipv6 * net.UDPConn
3032 blackhole4 bool
3133 blackhole6 bool
32- ipv4PC * ipv4.PacketConn
33- ipv6PC * ipv6.PacketConn
34+ ipv4PC * ipv4.PacketConn // will be nil on Windows
35+ ipv6PC * ipv6.PacketConn // will be nil on Windows
3436 udpAddrPool sync.Pool
3537 ipv4MsgsPool sync.Pool
3638 ipv6MsgsPool sync.Pool
@@ -184,8 +186,12 @@ again:
184186 return nil , 0 , syscall .EAFNOSUPPORT
185187 }
186188
187- s .ipv4PC = ipv4 .NewPacketConn (s .ipv4 )
188- s .ipv6PC = ipv6 .NewPacketConn (s .ipv6 )
189+ // x/net/ipv{4,6} packages do not implement PacketConn.{Read,Write}Batch()
190+ // for Windows (runtime error).
191+ if runtime .GOOS != "windows" {
192+ s .ipv4PC = ipv4 .NewPacketConn (s .ipv4 )
193+ s .ipv6PC = ipv6 .NewPacketConn (s .ipv6 )
194+ }
189195
190196 return fns , uint16 (port ), nil
191197}
@@ -196,9 +202,19 @@ func (s *StdNetBind) receiveIPv4(buffs [][]byte, sizes []int, eps []Endpoint) (n
196202 for i := range buffs {
197203 (* msgs )[i ].Buffers [0 ] = buffs [i ]
198204 }
199- numMsgs , err := s .ipv4PC .ReadBatch (* msgs , 0 )
200- if err != nil {
201- return 0 , err
205+ var numMsgs int
206+ if runtime .GOOS != "windows" {
207+ numMsgs , err = s .ipv4PC .ReadBatch (* msgs , 0 )
208+ if err != nil {
209+ return 0 , err
210+ }
211+ } else {
212+ msg := & (* msgs )[0 ]
213+ msg .N , msg .NN , _ , msg .Addr , err = s .ipv4 .ReadMsgUDP (msg .Buffers [0 ], msg .OOB )
214+ if err != nil {
215+ return 0 , err
216+ }
217+ numMsgs = 1
202218 }
203219 for i := 0 ; i < numMsgs ; i ++ {
204220 msg := & (* msgs )[i ]
@@ -217,9 +233,19 @@ func (s *StdNetBind) receiveIPv6(buffs [][]byte, sizes []int, eps []Endpoint) (n
217233 for i := range buffs {
218234 (* msgs )[i ].Buffers [0 ] = buffs [i ]
219235 }
220- numMsgs , err := s .ipv6PC .ReadBatch (* msgs , 0 )
221- if err != nil {
222- return 0 , err
236+ var numMsgs int
237+ if runtime .GOOS != "windows" {
238+ numMsgs , err = s .ipv6PC .ReadBatch (* msgs , 0 )
239+ if err != nil {
240+ return 0 , err
241+ }
242+ } else {
243+ msg := & (* msgs )[0 ]
244+ msg .N , msg .NN , _ , msg .Addr , err = s .ipv6 .ReadMsgUDP (msg .Buffers [0 ], msg .OOB )
245+ if err != nil {
246+ return 0 , err
247+ }
248+ numMsgs = 1
223249 }
224250 for i := 0 ; i < numMsgs ; i ++ {
225251 msg := & (* msgs )[i ]
@@ -301,12 +327,21 @@ func (s *StdNetBind) send4(conn *ipv4.PacketConn, ep Endpoint, buffs [][]byte) e
301327 err error
302328 start int
303329 )
304- for {
305- n , err = conn .WriteBatch ((* msgs )[start :len (buffs )], 0 )
306- if err != nil || n == len ((* msgs )[start :len (buffs )]) {
307- break
330+ if runtime .GOOS != "windows" {
331+ for {
332+ n , err = conn .WriteBatch ((* msgs )[start :len (buffs )], 0 )
333+ if err != nil || n == len ((* msgs )[start :len (buffs )]) {
334+ break
335+ }
336+ start += n
337+ }
338+ } else {
339+ for i , buff := range buffs {
340+ _ , _ , err = s .ipv4 .WriteMsgUDP (buff , (* msgs )[i ].OOB , ua )
341+ if err != nil {
342+ break
343+ }
308344 }
309- start += n
310345 }
311346 s .udpAddrPool .Put (ua )
312347 s .ipv4MsgsPool .Put (msgs )
@@ -330,12 +365,21 @@ func (s *StdNetBind) send6(conn *ipv6.PacketConn, ep Endpoint, buffs [][]byte) e
330365 err error
331366 start int
332367 )
333- for {
334- n , err = conn .WriteBatch ((* msgs )[start :len (buffs )], 0 )
335- if err != nil || n == len ((* msgs )[start :len (buffs )]) {
336- break
368+ if runtime .GOOS != "windows" {
369+ for {
370+ n , err = conn .WriteBatch ((* msgs )[start :len (buffs )], 0 )
371+ if err != nil || n == len ((* msgs )[start :len (buffs )]) {
372+ break
373+ }
374+ start += n
375+ }
376+ } else {
377+ for i , buff := range buffs {
378+ _ , _ , err = s .ipv6 .WriteMsgUDP (buff , (* msgs )[i ].OOB , ua )
379+ if err != nil {
380+ break
381+ }
337382 }
338- start += n
339383 }
340384 s .udpAddrPool .Put (ua )
341385 s .ipv6MsgsPool .Put (msgs )
0 commit comments