From 33b782a96d0fb1c82985c8bd5192f7a144b8877d Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Thu, 11 Aug 2022 20:55:50 -0500 Subject: [PATCH] Potential fix for Windows https://github.com/jackc/pgx/issues/1274 --- internal/nbconn/nbconn.go | 60 -------------------- internal/nbconn/nbconn_fake_non_block.go | 13 +++++ internal/nbconn/nbconn_real_non_block.go | 70 ++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 60 deletions(-) create mode 100644 internal/nbconn/nbconn_fake_non_block.go create mode 100644 internal/nbconn/nbconn_real_non_block.go diff --git a/internal/nbconn/nbconn.go b/internal/nbconn/nbconn.go index 16c4b713..c091ea3f 100644 --- a/internal/nbconn/nbconn.go +++ b/internal/nbconn/nbconn.go @@ -13,7 +13,6 @@ package nbconn import ( "crypto/tls" "errors" - "io" "net" "os" "sync" @@ -389,35 +388,6 @@ func (c *NetConn) fakeNonblockingWrite(b []byte) (n int, err error) { return c.conn.Write(b) } -// realNonblockingWrite does a non-blocking write. readFlushLock must already be held. -func (c *NetConn) realNonblockingWrite(b []byte) (n int, err error) { - c.nonblockWriteBuf = b - c.nonblockWriteN = 0 - c.nonblockWriteErr = nil - err = c.rawConn.Write(func(fd uintptr) (done bool) { - c.nonblockWriteN, c.nonblockWriteErr = syscall.Write(int(fd), c.nonblockWriteBuf) - return true - }) - n = c.nonblockWriteN - if err == nil && c.nonblockWriteErr != nil { - if errors.Is(c.nonblockWriteErr, syscall.EWOULDBLOCK) { - err = ErrWouldBlock - } else { - err = c.nonblockWriteErr - } - } - if err != nil { - // n may be -1 when an error occurs. - if n < 0 { - n = 0 - } - - return n, err - } - - return n, nil -} - func (c *NetConn) nonblockingRead(b []byte) (n int, err error) { if c.rawConn == nil { return c.fakeNonblockingRead(b) @@ -451,36 +421,6 @@ func (c *NetConn) fakeNonblockingRead(b []byte) (n int, err error) { return c.conn.Read(b) } -func (c *NetConn) realNonblockingRead(b []byte) (n int, err error) { - var funcErr error - err = c.rawConn.Read(func(fd uintptr) (done bool) { - n, funcErr = syscall.Read(int(fd), b) - return true - }) - if err == nil && funcErr != nil { - if errors.Is(funcErr, syscall.EWOULDBLOCK) { - err = ErrWouldBlock - } else { - err = funcErr - } - } - if err != nil { - // n may be -1 when an error occurs. - if n < 0 { - n = 0 - } - - return n, err - } - - // syscall read did not return an error and 0 bytes were read means EOF. - if n == 0 { - return 0, io.EOF - } - - return n, nil -} - // syscall.Conn is interface // TLSClient establishes a TLS connection as a client over conn using config. diff --git a/internal/nbconn/nbconn_fake_non_block.go b/internal/nbconn/nbconn_fake_non_block.go new file mode 100644 index 00000000..7e8b7634 --- /dev/null +++ b/internal/nbconn/nbconn_fake_non_block.go @@ -0,0 +1,13 @@ +//go:build !(aix || android || darwin || dragonfly || freebsd || hurd || illumos || ios || linux || netbsd || openbsd || solaris) + +package nbconn + +// Not using unix build tag for support on Go 1.18. + +func (c *NetConn) realNonblockingWrite(b []byte) (n int, err error) { + return fakeNonblockingWrite(b) +} + +func (c *NetConn) realNonblockingRead(b []byte) (n int, err error) { + return c.fakeNonblockingRead(b) +} diff --git a/internal/nbconn/nbconn_real_non_block.go b/internal/nbconn/nbconn_real_non_block.go new file mode 100644 index 00000000..ee48d129 --- /dev/null +++ b/internal/nbconn/nbconn_real_non_block.go @@ -0,0 +1,70 @@ +//go:build aix || android || darwin || dragonfly || freebsd || hurd || illumos || ios || linux || netbsd || openbsd || solaris + +package nbconn + +// Not using unix build tag for support on Go 1.18. + +import ( + "errors" + "io" + "syscall" +) + +// realNonblockingWrite does a non-blocking write. readFlushLock must already be held. +func (c *NetConn) realNonblockingWrite(b []byte) (n int, err error) { + c.nonblockWriteBuf = b + c.nonblockWriteN = 0 + c.nonblockWriteErr = nil + err = c.rawConn.Write(func(fd uintptr) (done bool) { + c.nonblockWriteN, c.nonblockWriteErr = syscall.Write(int(fd), c.nonblockWriteBuf) + return true + }) + n = c.nonblockWriteN + if err == nil && c.nonblockWriteErr != nil { + if errors.Is(c.nonblockWriteErr, syscall.EWOULDBLOCK) { + err = ErrWouldBlock + } else { + err = c.nonblockWriteErr + } + } + if err != nil { + // n may be -1 when an error occurs. + if n < 0 { + n = 0 + } + + return n, err + } + + return n, nil +} + +func (c *NetConn) realNonblockingRead(b []byte) (n int, err error) { + var funcErr error + err = c.rawConn.Read(func(fd uintptr) (done bool) { + n, funcErr = syscall.Read(int(fd), b) + return true + }) + if err == nil && funcErr != nil { + if errors.Is(funcErr, syscall.EWOULDBLOCK) { + err = ErrWouldBlock + } else { + err = funcErr + } + } + if err != nil { + // n may be -1 when an error occurs. + if n < 0 { + n = 0 + } + + return n, err + } + + // syscall read did not return an error and 0 bytes were read means EOF. + if n == 0 { + return 0, io.EOF + } + + return n, nil +}