connCheck checks if the connection is still alive and if there is data in the socket it will try to peek at the next byte without consuming it since we may want to work with it later on (e.g. push notifications)
(conn net.Conn)
| 16 | // it will try to peek at the next byte without consuming it since we may want to work with it |
| 17 | // later on (e.g. push notifications) |
| 18 | func connCheck(conn net.Conn) error { |
| 19 | // Reset previous timeout. |
| 20 | _ = conn.SetDeadline(time.Time{}) |
| 21 | |
| 22 | sysConn, ok := conn.(syscall.Conn) |
| 23 | if !ok { |
| 24 | return nil |
| 25 | } |
| 26 | rawConn, err := sysConn.SyscallConn() |
| 27 | if err != nil { |
| 28 | return err |
| 29 | } |
| 30 | |
| 31 | var sysErr error |
| 32 | |
| 33 | if err := rawConn.Read(func(fd uintptr) bool { |
| 34 | var buf [1]byte |
| 35 | // Use MSG_PEEK to peek at data without consuming it |
| 36 | n, _, err := syscall.Recvfrom(int(fd), buf[:], syscall.MSG_PEEK|syscall.MSG_DONTWAIT) |
| 37 | |
| 38 | switch { |
| 39 | case n == 0 && err == nil: |
| 40 | sysErr = io.EOF |
| 41 | case n > 0: |
| 42 | sysErr = errUnexpectedRead |
| 43 | case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK: |
| 44 | sysErr = nil |
| 45 | default: |
| 46 | sysErr = err |
| 47 | } |
| 48 | return true |
| 49 | }); err != nil { |
| 50 | return err |
| 51 | } |
| 52 | |
| 53 | return sysErr |
| 54 | } |
| 55 | |
| 56 | // maybeHasData checks if there is data in the socket without consuming it |
| 57 | func maybeHasData(conn net.Conn) bool { |
no test coverage detected