fix: use socket.fromfd in send_batch_sync for Python 3.13 compat

Python 3.13's asyncio TransportSocket wrapper rejects setblocking(). Dup
the underlying fd via socket.fromfd() into a plain socket that the
executor thread can drive in blocking mode, then detach() after the
batch to avoid closing the transport's fd.
This commit is contained in:
YueGuobin 2026-08-11 01:10:18 +08:00
parent f9f1a4d4d8
commit 46bad0b639
No known key found for this signature in database

View File

@ -20,6 +20,7 @@ import logging
import asyncio
import threading
import concurrent.futures
import socket as _socket
from gns3server.utils.asyncio import locking
from .ubridge_error import UbridgeError
@ -296,10 +297,15 @@ class UBridgeHypervisor:
transport = self._writer.transport
if transport is None or transport.is_closing():
raise UbridgeError("Transport closed")
sock = transport.get_extra_info("socket")
if sock is None:
tr_sock = transport.get_extra_info("socket")
if tr_sock is None:
raise UbridgeError("No underlying socket for sync send_batch")
# Python 3.13's transport socket wrapper (trsock) rejects
# setblocking(), so dup the underlying fd into a plain socket
# that the executor thread can drive in blocking mode.
sock = _socket.fromfd(tr_sock.fileno(), tr_sock.family, _socket.SOCK_STREAM)
# Serialise access to this hypervisor's socket — only one batch (sync
# or async) talks to uBridge at a time. The node-level async lock
# (:func:`_ubridge_send`) is held for the entire executor call, so no
@ -343,3 +349,4 @@ class UBridgeHypervisor:
self._recv_buf = b""
finally:
sock.setblocking(False)
sock.detach() # release the dup'd fd, don't close transport