Skip to content

[BUG] presence_callinfo: line-seize accepted for an appearance already in an active call #4193

Description

@briscocom

OpenSIPS version you are running

version: opensips 3.6.7 (x86_64/linux)
flags: STATS: On, DISABLE_NAGLE, USE_MCAST, SHM_MMAP, PKG_MALLOC, Q_MALLOC, F_MALLOC, HP_MALLOC, F_PARALLEL_MALLOC, DBG_MALLOC, FAST_LOCK-ADAPTIVE_WAIT
ADAPTIVE_WAIT_LOOPS=1024, MAX_RECV_BUFFER_SIZE 262144, MAX_LISTEN 16, MAX_URI_SIZE 1024, BUF_SIZE 65535
poll method support: poll, epoll, sigio_rt, select.
git revision: eaee48e28e
main.c compiled on  with gcc 10

Observed on 3.6.7. Master retains the missing per-index-state check and the unchecked
assignment/publish sequence in lineseize_subs_handl, but its outbound caller path differs,
so the reproduction below applies to 3.6.7 only. I am separately re-verifying master runtime
behaviour. This issue is independent of the inverted expiry test in lineseize_subs_handl,
corrected on master by 3595af48; the 3.6.7 reproduction below was run with the equivalent
correction applied.

Describe the bug

A line-seize SUBSCRIBE for an appearance index that is already in an active call is
accepted with 200 OK. This is the case the existing FIXME in lineseize_subs_handl
describes:

/* FIXME - check the seized idx is not already in a call */
/* do the seizing */
sca->seize_state = idx;

The 3.6.7 reproduction reaches the handler because line seizure and per-index call state are
tracked separately. sca_set_calling_line() enters sca_set_line(), which, for the
still-valid seizure used in this reproduction, invokes terminate_line_sieze() and clears
seize_state. After the dialog confirms, its callback publishes that index as active. A
subsequent initial line-seize therefore skips the existing-seizure block because
seize_state == 0. With the per-index check named by the FIXME absent, the handler assigns
the index, changes its state to SCA_STATE_SEIZED, and publishes it.

Master has a different caller path. Commit 283b529c removed the exported
sca_set_calling_line(), introduced sca_engage(), and introduced sca_validate_call_out().
That validator unlocks the line without clearing the seizure; its only in-tree
terminate_line_sieze() invocation is a comment positioned after the unlock. Consequently,
sca_engage("A") does not perform the 3.6 call-time clear. Master retains the missing
per-index-state check and unchecked assignment/publish sequence, but I am re-verifying a
master-specific runtime trigger before making a reachability claim.

There is a second effect on the published state. set_sca_index_state() overwrites the
per-index entry in place (scai->state = state), so accepting the seize replaces active
with seized rather than conflicting with it — the in-progress call is no longer
represented in the published appearance state at all.

To Reproduce

With disable_dialog_support_for_sca=0 (internal publishing mode):

  1. Endpoint P1 sends a line-seize SUBSCRIBE for appearance-index=3200 OK
    (seize_state = 3).
  2. P1 sends an INVITE from the line carrying Call-Info: <line>;appearance-index=3.
    sca_set_calling_line() terminates the seizure (seize_state → 0); the callee answers,
    the dialog confirms, and index 3 becomes active.
  3. Endpoint P2 sends a line-seize SUBSCRIBE for appearance-index=3, while index 3 is in
    the active call.

Observed:

p1_seize_status:                 200
invite_status:                   200
index_state_after_call:          active
p2_seize_of_active_index_status: 200      <-- accepted while active

Both endpoints are software endpoints (sipp); no external SIP service is involved.

Expected behavior

A line-seize for an appearance that is already in an active call should not be granted,
and accepting a seize should not discard the appearance's existing call state in the
published NOTIFY.

Relevant System Logs

The published call-info NOTIFY after P2's accepted seize:

Call-Info: <sip:LINE>;appearance-index=3;appearance-state=seized;appearance-index=*;appearance-state=idle

Index 3 is published as seized only; the active state it held before P2's SUBSCRIBE is
gone, so watchers of the line no longer see the call in progress.

OS/environment information

  • Operating System: Debian (container image)
  • OpenSIPS installation: source, built from tag 3.6.7 (eaee48e28e)
  • other relevant information: presence_callinfo in internal publishing mode
    (disable_dialog_support_for_sca=0); software endpoints only.

Additional context

We have a candidate patch that checks the index's current state before accepting the seize,
along with regression results, and are happy to open a PR if that shape is useful. We have
not done so because the right semantics look like a design decision rather than an obvious
fix — in particular whether a seize should be refused for every non-idle appearance, or only
for one in an active call. Seizing an appearance that is on hold appears to be a
legitimate way to resume or pick up that call, and deliberate barge-in is a real feature, so
a guard that rejects all non-idle states could break behaviour that is intended. Happy to
follow whichever direction you prefer.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions