connect_check.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. // +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos
  2. package clickhouse
  3. import (
  4. "errors"
  5. "fmt"
  6. "io"
  7. "syscall"
  8. "time"
  9. )
  10. var errUnexpectedRead = errors.New("unexpected read from socket")
  11. func (conn *connect) connCheck() error {
  12. var sysErr error
  13. sysConn, ok := conn.Conn.(syscall.Conn)
  14. if !ok {
  15. return nil
  16. }
  17. rawConn, err := sysConn.SyscallConn()
  18. if err != nil {
  19. return err
  20. }
  21. // If this connection has a ReadTimeout which we've been setting on
  22. // reads, reset it to zero value before we attempt a non-blocking
  23. // read, otherwise we may get os.ErrDeadlineExceeded for the cached
  24. // connection from the pool with an expired timeout.
  25. if conn.readTimeout != 0 {
  26. err = conn.SetReadDeadline(time.Time{})
  27. if err != nil {
  28. return fmt.Errorf("set read deadline: %w", err)
  29. }
  30. conn.lastReadDeadlineTime = time.Time{}
  31. }
  32. err = rawConn.Read(func(fd uintptr) bool {
  33. var buf [1]byte
  34. n, err := syscall.Read(int(fd), buf[:])
  35. switch {
  36. case n == 0 && err == nil:
  37. sysErr = io.EOF
  38. case n > 0:
  39. sysErr = errUnexpectedRead
  40. case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK:
  41. sysErr = nil
  42. default:
  43. sysErr = err
  44. }
  45. return true
  46. })
  47. if err != nil {
  48. return err
  49. }
  50. return sysErr
  51. }