fix(server): macOS UDP search port sharing + init handlers without data#5
Merged
MatInGit merged 1 commit intoISISNeutronMuon:mainfrom Apr 16, 2026
Conversation
Two related server fixes for running an IOC co-located with other PVA clients (notably p4p) on macOS: 1. UDP search port: add bind_udp_search_socket() helper that uses socket2 to set SO_REUSEADDR + SO_REUSEPORT (Unix) before binding. Without SO_REUSEPORT, macOS rejects a second process trying to bind the well-known search port (5076), preventing p4p / pvmonitor from starting on the same host as the spvirit IOC. Linux has the same requirement for live multi-bind (>= 3.9). handler.rs and the spserver / spdodeca CLI binaries now share the same helper. 2. MONITOR / PUT / PUT_GET init: previously these init paths returned "PV not found" whenever get_nt_snapshot returned None, which strict clients like p4p treat as fatal for the whole subscription / transaction. Following the pattern already applied to GET init, these handlers now try PvStore::get_descriptor first so clients can initialise against PVs that have no data yet (e.g. NTNDArray before the first acquire). "PV not found" is only returned when neither a descriptor nor a snapshot is available.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
When running a
spvirit-serverIOC alongside other PVAccess consumers on the same macOS host (e.g.p4p-based PyDM image viewers,pvmonitor), two issues prevent the stack from working end-to-end:EADDRINUSEand the PVA plugin never loads.p4ptear the subscription down on the initial "PV not found" error and never recover, even after data eventually arrives. The most common trigger is an NTNDArray PV before the camera starts acquiring.Root cause:
handler.rs::run_udp_searchcalledUdpSocket::bind(addr)directly. NoSO_REUSEADDR/SO_REUSEPORT. On macOS/BSD (and Linux ≥ 3.9) live multi-bind on the same UDP port requiresSO_REUSEPORTon every participant — if the server doesn't set it, later clients cannot join. The CLI binariesspserverandspdodecahad the same duplicated code path.get_nt_snapshotand returnedencode_op_error("PV not found", ...)when the snapshot wasNone. PVA semantics for init only require the type descriptor, not a live value — lenient clients (pvmonitor-rs) tolerate the error and keep waiting, butp4ptreats the init error as fatal. Upstream already fixed this for GET init in 3918bb1 but did not propagate the same pattern to the other init paths.Changes
1. UDP search port: shareable bind
pub fn bind_udp_search_socket(addr)inspvirit-server/src/handler.rs. Usessocket2to setSO_REUSEADDR+SO_REUSEPORT(Unix) and converts back to atokio::net::UdpSocket.run_udp_search(library and both CLI binaries) now goes through this helper.beacon.rsnot touched — it binds:0(ephemeral, send-only), so there is no port to share.2. Init handlers: tolerate data-less PVs
PvStore::get_descriptorfirst, fall back to deriving the descriptor fromget_nt_snapshot, and only return"PV not found"when both areNone. Mirrors the existing GET init logic from 3918bb1.