Skip to content

plugin: one HTTP server per BinaryView - #20

Open
BlasterXiao wants to merge 5 commits into
0xeb:mainfrom
BlasterXiao:feature/multi-view-http-servers
Open

BlasterXiao wants to merge 5 commits into
0xeb:mainfrom
BlasterXiao:feature/multi-view-http-servers

Conversation

@BlasterXiao

Copy link
Copy Markdown

The GUI plugin kept a single process-wide HTTP server, bound to whichever view was active when it was started. With several files open in tabs, only one of them could be queried over HTTP.

Track servers in a registry keyed by BinaryView instead:

  • Start HTTP Server binds a new server to the current tab's view; starting again on a tab that already has one reports its port.
  • Stop HTTP Server stops only the current tab's server and lists servers for other tabs when the current one has none.
  • HTTP Server Status lists every running server with port and file name.
  • Entries whose server was stopped remotely (POST /shutdown) are pruned.

Statement execution stays serialized across all servers through one shared mutex, since runtime settings and the timeout stack are process-wide. The /status function count is read from the view directly so the GUI thread never waits on that mutex.

BlasterXiao and others added 5 commits October 16, 2026 13:41
The GUI plugin kept a single process-wide HTTP server, bound to whichever
view was active when it was started. With several files open in tabs, only
one of them could be queried over HTTP.

Track servers in a registry keyed by BinaryView instead:
- Start HTTP Server binds a new server to the current tab's view; starting
  again on a tab that already has one reports its port.
- Stop HTTP Server stops only the current tab's server and lists servers
  for other tabs when the current one has none.
- HTTP Server Status lists every running server with port and file name.
- Entries whose server was stopped remotely (POST /shutdown) are pruned.

Statement execution stays serialized across all servers through one shared
mutex, since runtime settings and the timeout stack are process-wide. The
/status function count is read from the view directly so the GUI thread
never waits on that mutex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Start HTTP Server...: an empty port (or "host:" with no port) now takes
  the first free port from 8080, skipping ports held by other bnsql servers
  or by other processes. Explicit ports and 0 (random) behave as before.
- New "Start HTTP Servers for All Tabs": starts a loopback server on an
  automatically chosen port for every open tab that has no server yet, with
  no prompts, then shows a port -> file summary. Open tabs are listed through
  Binary Ninja's bundled Python (the core API has no "open views" query),
  the same mechanism the ui-context capture uses; it runs on a worker thread
  because the snippet marshals to the GUI thread.
- Server construction moved into CreateHTTPServer() so both commands share it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The HTTP server binds with SO_REUSEADDR. On Windows that lets the bind succeed
on a port another process also opened with SO_REUSEADDR, so both would listen
on the same port and the automatic pick would not notice the conflict.

Probe each candidate port with an exclusive bind (SO_EXCLUSIVEADDRUSE on
Windows, a plain bind elsewhere) before starting the server:
- automatic picks skip ports another program holds, whatever options it used;
- an explicit port that is already taken is refused with a message suggesting
  an empty port instead of silently sharing it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the GUI plugin, SELECT save() ran SaveAutoSnapshot on the HTTP worker
thread. Binary Ninja then showed "Error while saving database snapshot:
Unable to read file contents to store into database" from its main thread,
although the snapshot was written. The same save marshalled to the main
thread (where File > Save runs) shows no error; a worker-thread save on
another tab reproduced the dialog in the same session.

save_binary_view() now uses ExecuteOnMainThreadAndWait when the UI is
enabled and the caller is not already on the main thread. Headless hosts
(CLI) are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Marshalling save() to the main thread alone did not stop the GUI's
"Unable to read file contents to store into database" dialog. Binary
Ninja's Python FileMetadata.save_auto_snapshot()/create_database() pass the
file's Raw view to the core, while bnsql passed the analysed view (PE).
Tested in the GUI: Raw view on the main thread saved without the dialog;
Raw view off the main thread, and PE view on the main thread, both still
showed it. Use file->GetViewOfType("Raw") (falling back to the given view)
for CreateDatabase and SaveAutoSnapshot, and keep the main-thread save.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant