fix: Eliminate blocking HTTP call from instances_use
instances_use previously called register_instance which made a blocking safe_get (30s timeout) to validate the connection. If the Ghidra server was slow or unresponsive, this could hang the MCP tool call indefinitely from the client's perspective. Now instances_use creates a lazy stub entry and sets the port immediately — pure in-memory, no network I/O. The first actual tool call validates the connection naturally. Also fix background discovery thread using request_timeout (30s) instead of discovery_timeout (0.5s) per port — worst case went from 300s to 5s per scan cycle.
This commit is contained in:
parent
c93abaf86c
commit
458d4fb35b
@ -166,13 +166,20 @@ class InstancesMixin(GhydraMixinBase):
|
|||||||
Returns:
|
Returns:
|
||||||
Confirmation message with instance details
|
Confirmation message with instance details
|
||||||
"""
|
"""
|
||||||
|
# Register lazily without blocking HTTP calls.
|
||||||
|
# If the instance is unknown, create a stub entry — the first
|
||||||
|
# actual tool call (functions_list, etc.) will validate the
|
||||||
|
# connection and fail fast with a clear error if unreachable.
|
||||||
with self._instances_lock:
|
with self._instances_lock:
|
||||||
needs_register = port not in self._instances
|
if port not in self._instances:
|
||||||
|
config = get_config()
|
||||||
if needs_register:
|
self._instances[port] = {
|
||||||
result = self.register_instance(port)
|
"url": f"http://{config.ghidra_host}:{port}",
|
||||||
if "Failed" in result or "Error" in result:
|
"project": "",
|
||||||
return result
|
"file": "",
|
||||||
|
"registered_at": time.time(),
|
||||||
|
"lazy": True,
|
||||||
|
}
|
||||||
|
|
||||||
self.set_current_port(port)
|
self.set_current_port(port)
|
||||||
|
|
||||||
|
|||||||
@ -105,10 +105,14 @@ def create_server(
|
|||||||
def _periodic_discovery(interval: int = 30):
|
def _periodic_discovery(interval: int = 30):
|
||||||
"""Background thread for periodic instance discovery.
|
"""Background thread for periodic instance discovery.
|
||||||
|
|
||||||
|
Uses a short timeout per port so a full scan completes quickly
|
||||||
|
even when most ports are unreachable.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
interval: Seconds between discovery attempts
|
interval: Seconds between discovery attempts
|
||||||
"""
|
"""
|
||||||
from .core.http_client import safe_get
|
import requests as _requests
|
||||||
|
|
||||||
from .mixins.base import GhydraMixinBase
|
from .mixins.base import GhydraMixinBase
|
||||||
|
|
||||||
config = get_config()
|
config = get_config()
|
||||||
@ -116,15 +120,22 @@ def _periodic_discovery(interval: int = 30):
|
|||||||
while True:
|
while True:
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
try:
|
try:
|
||||||
# Quick scan of common ports
|
# Quick scan — use discovery_timeout (0.5s), NOT request_timeout (30s)
|
||||||
for port in config.quick_discovery_range:
|
for port in config.quick_discovery_range:
|
||||||
try:
|
try:
|
||||||
response = safe_get(port, "")
|
url = f"http://{config.ghidra_host}:{port}/"
|
||||||
|
resp = _requests.get(
|
||||||
|
url,
|
||||||
|
timeout=config.discovery_timeout,
|
||||||
|
headers={"Accept": "application/json"},
|
||||||
|
)
|
||||||
|
if resp.ok:
|
||||||
|
response = resp.json()
|
||||||
if response.get("success", False):
|
if response.get("success", False):
|
||||||
with GhydraMixinBase._instances_lock:
|
with GhydraMixinBase._instances_lock:
|
||||||
if port not in GhydraMixinBase._instances:
|
if port not in GhydraMixinBase._instances:
|
||||||
GhydraMixinBase._instances[port] = {
|
GhydraMixinBase._instances[port] = {
|
||||||
"url": f"http://{config.ghidra_host}:{port}",
|
"url": url.rstrip("/"),
|
||||||
"project": response.get("project", ""),
|
"project": response.get("project", ""),
|
||||||
"file": response.get("file", ""),
|
"file": response.get("file", ""),
|
||||||
"discovered_at": time.time(),
|
"discovered_at": time.time(),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user