Skip to content

Accept() closes the listener socket on success — a listener can only accept one connection #79

Description

@cdgraff

Summary

NodeSRT::Accept() (in src/node-srt.cc) calls srt_close() on the listener socket on the success path, so the listening socket is destroyed after every accepted connection. This makes it impossible to accept more than one connection from a single listener without re-creating it.

Details

Napi::Value NodeSRT::Accept(const Napi::CallbackInfo& info) {
  ...
  int their_fd = srt_accept(socketValue, (struct sockaddr *)&their_addr, &addr_size);
  if (their_fd == SRT_INVALID_SOCK) {
    srt_close(socketValue);      // failure path
    ...
    return Napi::Number::New(env, SRT_ERROR);
  }
  srt_close(socketValue);        // <-- success path: closes the LISTENER
  socketValue = Napi::Number::New(env, SRT_INVALID_SOCK);
  return Napi::Number::New(env, their_fd);
}

In libsrt, srt_accept() returns the newly accepted socket and leaves the listener open so it can keep accepting. Closing the listener here diverges from that contract.

Impact

  • A server can accept only one connection per listener; after the first accept() the listener goes to SRT_SOCKSTATUS BROKEN and subsequent callers time out.
  • To work around it, apps must re-create (bind+listen) the listener after every accept. That drops the listener's backlog of pending handshakes, so when several callers connect at nearly the same time, only one is accepted and the rest fail with an I/O error (their handshakes are lost when the listener is destroyed). This is very visible under a burst of simultaneous connections (e.g. after a restart), where the large majority of callers fail to connect.

Reproduction

  1. Create a listener (createSocketbindlistenepollAddUsock).
  2. Connect one caller; call accept(listenerFd).
  3. Check getSockState(listenerFd) immediately after: it is BROKEN (6), then NONEXIST (9). Any further caller times out.

With the success-path srt_close removed, the listener stays LISTENING (3) and accepts multiple connections normally (verified: 1/3 → 3/3 sequential callers; and a burst of N simultaneous callers goes from ~1/N to N/N).

Suggested fix

Remove the srt_close(socketValue) (and the following no-op reassignment) on the success path, so Accept() only returns the accepted fd and leaves the listener open — matching libsrt semantics. The caller is responsible for closing the listener when done.

Happy to open a PR if that helps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions