相关文章推荐
失落的木瓜  ·  Python报错:PermissionErr ...·  3 月前    · 
爱笑的汉堡包  ·  域套接字sendto errno ...·  3 周前    · 
发财的太阳  ·  Managing Credentials ...·  1 月前    · 
读研的肉夹馍  ·  Audacity ® | Download ...·  8 月前    · 
严肃的枕头  ·  毕马威中国: 主页·  10 月前    · 
长情的豆腐  ·  bootstrap-datetimepick ...·  1 年前    · 

OSError: [Errno 9] Bad file descriptor on socket.shutdown(socket.SHUT_RDWR) #597

@webknjaz

Description

I'm submitting a ...

  • 🐞 bug report
  • 🐣 feature request
  • ❓ question about the decisions made in the repository
  • 🐞 Describe the bug. What is the current behavior?

    Sometimes, sending a TCP FIN over a socket, errors out with OSError: [Errno 9] Bad file descriptor . The exception originates at https://github.com/cherrypy/cheroot/blob/57fc412/cheroot/server.py#L1480 and is re-raised at https://github.com/cherrypy/cheroot/blob/57fc412/cheroot/server.py#L1484-L1485 since the corresponding syscall return code ( errno.EBADF / 9 ) is not listed as allowed to be ignored. We may need to reconsider what's ignored there.
    I noticed this in one of the recent CI runs, and it does not appear to be reoccurring, but I'm still filing this issue to log that this has happened.

    What is the motivation / use case for changing the behavior?

    Clean runtime operation.

    💡 To Reproduce

    Not clear.

    💡 Expected behavior

    No exception logged .

    📋 Details

    This is what's visible in the CI log:

    >           assert c_msg in raw_testing_server.error_log.ignored_msgs, (
                    'Found error in the error log: '
                    "message = '{c_msg}', level = '{c_level}'\n"
                    '{c_traceback}'.format(**locals()),
    E           AssertionError: ("Found error in the error log: message = 'Error in HTTPServer.serve', level = '40'
    E             Traceback (most recent call last)...e_kernel_socket
    E                 shutdown(socket.SHUT_RDWR)  # actually send a TCP FIN
    E             OSError: [Errno 9] Bad file descriptor
    E             ",)
    E           assert 'Error in HTTPServer.serve' in []
    E            +  where [] = <cheroot.test.test_conn.ErrorLogMonitor object at 0x10906e4f0>.ignored_msgs
    E            +    where <cheroot.test.test_conn.ErrorLogMonitor object at 0x10906e4f0> = <cheroot.wsgi.Server object at 0x10906ef10>.error_log

    It's not clear why exactly this is happening but googling suggests that the underlying syscall is what returns [Errno 9] Bad file descriptor . https://man7.org/linux/man-pages/man2/shutdown.2.html includes the following:

    ERRORS

    EBADF sockfd is not a valid file descriptor.

    Which may mean that the underlying file descriptor for the socket in question may have been closed prior to this call somehow. It's interesting that this error is separate from

    ENOTCONN
    The specified socket is not connected.

    and ENOTCONN is listed as needed to be ignored at

    cheroot/cheroot/errors.py Lines 59 to 78 57fc412

    OTOH, looking at https://github.com/python/cpython/blob/e56e33d271e511e7c2324640d7f49d39b49830d8/Lib/test/support/asyncore.py#L66-L67 , it suggests that errno.EBADF might also happen for disconnected sockets but there's no comment explaining when that happens...
    python/cpython@ 900d547 and https://mail.python.org/pipermail/python-dev/2011-February/108005.html suggest that there are cases when shutdown is called twice (so another call made after the initial shutdown might cause errno.EBADF , eh?).

    The initial additions seem to be unexplained @ python/cpython@ d74900e #diff-01ee2588a875a4eae9f82d026b861a3e95bbf3b8024085bbe938c3c006443512R382 and another patch adding the same @ python/cpython@ 0abc64d refers to some macOS quirks (could this be our case?). The folks discussing the bug linked in the latter commit ( https://bugs.python.org/issue5798 / python/cpython#50048 ) seems to be hesitant as to whether EBADF always means a “disconnected socket” semantically, though: https://bugs.python.org/msg87477 / python/cpython#50048 (comment) .

    I was also concerned by the test in question ( cheroot/test/test_conn.py::test_invalid_selected_connection ) sabotaging the connection influencing this, but couldn't come up with an explanation of how it could damage the underlying kernel socket so it's likely not the cause of this traceback.

    Oh.. And there's one more place in Cheroot where the shutdown is called, but it seems like it's happening on the final cleanup, not prior to the shutdown in question: