python / python/cpython

Endless polling EOF socket

Abierto
#148,950 9 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

stdlib type-bug
Lenguaje dominante
Python
Estrellas
77.2k
Forks
35.9k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

Bug report

Bug description:

Hello,

I have this very simple code to attempt a TCP connection to a given host. The linux machine where I run this has tsocks library installed, to transparently redirect connections over socks server. If the target IP accessed through the socks server refuses the connection, the code will end in an endless unbreakable loop.

def tcp_connect(ip, port):
    """Attempt a TCP connection to the given IP and port."""
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(5)
        result = sock.connect_ex((ip, port))
        sock.close()

Timeout has no effect, ctrl+c on the console doesn't break it.

Connection attempt with some command line utility ends correctly.

$ ssh 1.1.1.1
ssh: connect to host 1.1.1.1 port 22: Transport endpoint is not connected
$ ldp telnet 1.1.1.1 22
Trying 1.1.1.1...
telnet: Unable to connect to remote host: Transport endpoint is not connected

I tried running strace to see what happens during that endless loop and this is the result :

getpeername(3, 0x7ffd6c12e3f0, [16])    = -1 ENOTCONN (Transport endpoint is not connected)
connect(3, {sa_family=AF_INET, sin_port=htons(2224), sin_addr=inet_addr("172.17.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
poll([{fd=3, events=POLLOUT}], 1, 5000) = 1 ([{fd=3, revents=POLLOUT}])
connect(3, {sa_family=AF_INET, sin_port=htons(2224), sin_addr=inet_addr("172.17.0.1")}, 16) = 0
sendto(3, "\5\2\0\2", 4, 0, NULL, 0)    = 4
recvfrom(3, "\5\0", 2, 0, NULL, NULL)   = 2
sendto(3, "\5\1\0\1\225\203f\211\0\26", 10, 0, NULL, 0) = 10
recvfrom(3, 0x55944406ddd8, 10, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=3, events=POLLIN}], 1, 5000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 10, 0, NULL, NULL)      = 0
poll([{fd=3, events=POLLIN}], 1, 5000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 10, 0, NULL, NULL)      = 0
poll([{fd=3, events=POLLIN}], 1, 5000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 10, 0, NULL, NULL)      = 0
poll([{fd=3, events=POLLIN}], 1, 5000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 10, 0, NULL, NULL)      = 0
poll([{fd=3, events=POLLIN}], 1, 5000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 10, 0, NULL, NULL)      = 0

<continues until sigkill while hogging 100% CPU>

I don't understand it that much, but LLM seems to believe, that the socket is getting polled despite EOF, which is supposedly an error.

Edit:
For comparison, this is how the strace on that telnet looks like

getpeername(3, 0x7ffd4d54e260, [16])    = -1 ENOTCONN (Transport endpoint is not connected)
connect(3, {sa_family=AF_INET, sin_port=htons(2224), sin_addr=inet_addr("172.17.0.1")}, 16) = 0
sendto(3, "\5\2\0\2", 4, 0, NULL, 0)    = 4
recvfrom(3, "\5\0", 2, 0, NULL, NULL)   = 2
sendto(3, "\5\1\0\1\225\203f\211\0\26", 10, 0, NULL, 0) = 10
recvfrom(3, "", 10, 0, NULL, NULL)      = 0
write(2, "telnet: Unable to connect to rem"..., 78telnet: Unable to connect to remote host: Transport endpoint is not connected
) = 78
close(3)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++

Thank you for your attention.

CPython versions tested on:

3.10

Operating systems tested on:

Linux

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con el fragmento tcp_connect del informe y reprodúcelo en Linux con Python 3.10 y tsocks; después, compara su strace con el caso funcional de telnet. Rastrea el comportamiento de socket y connect_ex alrededor de las lecturas EOF repetidas para determinar si el bucle está en CPython o en la capa de proxy transparente. Se considera terminado cuando se haya identificado el comportamiento responsable y el issue tenga una prueba de regresión reproducible o una resolución clara.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
networking
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Tranquilo
Claridad
Necesita aclaración
Aptitud para principiantes
45/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.