trpc.group/trpc-go/trpc-go@v1.0.3/pool/connpool/checker_unix.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  //go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris || linux
    15  // +build aix darwin dragonfly freebsd netbsd openbsd solaris linux
    16  
    17  package connpool
    18  
    19  import (
    20  	"errors"
    21  	"io"
    22  	"net"
    23  	"syscall"
    24  
    25  	"trpc.group/trpc-go/trpc-go/internal/report"
    26  )
    27  
    28  func checkConnErr(conn net.Conn, buf []byte) error {
    29  	return checkConnErrUnblock(conn, buf)
    30  }
    31  
    32  func checkConnErrUnblock(conn net.Conn, buf []byte) error {
    33  	sysConn, ok := conn.(syscall.Conn)
    34  	if !ok {
    35  		return nil
    36  	}
    37  	rawConn, err := sysConn.SyscallConn()
    38  	if err != nil {
    39  		return err
    40  	}
    41  
    42  	var sysErr error
    43  	var n int
    44  	err = rawConn.Read(func(fd uintptr) bool {
    45  		// Go sets the socket to non-blocking mode by default, and calling syscall can return directly.
    46  		// Refer to the Go source code: sysSocket() function under src/net/sock_cloexec.go
    47  		n, sysErr = syscall.Read(int(fd), buf)
    48  		// Return true, the blocking and waiting encapsulated by
    49  		// the net library will not be executed, and return directly.
    50  		return true
    51  	})
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	// connection is closed, return io.EOF.
    57  	if n == 0 && sysErr == nil {
    58  		report.ConnectionPoolRemoteEOF.Incr()
    59  		return io.EOF
    60  	}
    61  	// Idle connections should not read data.
    62  	if n > 0 {
    63  		return errors.New("unexpected read from socket")
    64  	}
    65  	// Return to EAGAIN or EWOULDBLOCK if the idle connection is in normal state.
    66  	if sysErr == syscall.EAGAIN || sysErr == syscall.EWOULDBLOCK {
    67  		return nil
    68  	}
    69  	return sysErr
    70  }