Skip to content

Add rs-metadata update support for SIPREC mid-dialog requests - #5206

Open
sorooshm78 wants to merge 5 commits into
pjsip:masterfrom
sorooshm78:Feature/siprec-metadata-update-support
Open

Add rs-metadata update support for SIPREC mid-dialog requests#5206
sorooshm78 wants to merge 5 commits into
pjsip:masterfrom
sorooshm78:Feature/siprec-metadata-update-support

Conversation

@sorooshm78

Copy link
Copy Markdown
Contributor

Summary

Add support for SIPREC rs-metadata document updates during mid-dialog re-INVITE and UPDATE requests, enabling SRS to track metadata changes throughout the recording session lifecycle as required by RFC 7866.

Changes

  • Add on_siprec_metadata_update callback to pjsip_inv_callback and siprec_metadata field to pjsip_inv_session for tracking metadata changes
  • Add pjsip_siprec_verify_update() and pjsip_siprec_parse_data_mode() functions to process and validate mid-dialog metadata updates
  • Integrate metadata processing into UPDATE and re-INVITE handlers with refactored shared helper function
  • Fix media type priority per RFC 9806: prefer application/rs-metadata+xml, accept legacy application/rs-metadata with deprecation warning

Motivation

RFC 7866 Section 4.5 requires that SRS must be able to receive and process metadata updates during the lifetime of a Communication Session (CS). The original implementation only processed metadata in the initial INVITE, ignoring mid-dialog updates. This enables tracking participant changes, permission updates, and other metadata changes during recording.

Reference

@nanangizz nanangizz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow-up work on this — mid-dialog metadata handling is genuinely missing today, and the RFC 9806 media-type reordering in pjsip_siprec_get_metadata() is a good catch and correct.

I built the branch with PJSUA_HAS_SIPREC=1 (clean, no new warnings) and traced the touched paths. The build passing hides a few real defects, so I'd like these addressed before merging. Details are in the inline comments; summarising the blocking ones:

  1. pjsip_siprec_parse_data_mode() can never detect a partial update. It looks for the literal "dataMode" parsed as an XML attribute, but RFC 7865 defines dataMode only as the XSD type name — the document construct is the lowercase element <datamode>partial</datamode>. Case-sensitive match plus attribute-style parsing means a conformant document always yields is_complete = PJ_TRUE.
  2. Use-after-free in pjsua_call.c — the metadata copy is allocated from inv->pool_prov, which inv_negotiate_sdp() resets after every negotiation.
  3. A failed metadata check can leave the request unanswered, hanging the UAS transaction until timer-B/H.
  4. A metadata-only UPDATE (no SDP) is answered 488 — that is arguably the main use case for this feature per RFC 7866 §7.1.
  5. inv->pool grows unboundedly — one permanent allocation per metadata update on the long-term pool.

There are also no tests. pjsip/src/test/pjsua_call_test.c already has a SIPREC section exercising siprec_require_metadata; a mid-dialog re-INVITE/UPDATE case belongs there and would have caught items 1 and 4 straight away.

Style: 8 added lines exceed 80 columns (1 in sip_siprec.h, 2 in sip_inv.c, 5 in sip_siprec.c), and the new prototypes' continuation lines are indented one space past the open paren — please see the coding style guide.

Minor: the description says "Fixes #5024", but that is a PR rather than an issue — I think you mean it supersedes it.

Comment thread pjsip/src/pjsip-ua/sip_siprec.c Outdated
Comment thread pjsip/src/pjsip-ua/sip_siprec.c Outdated
Comment thread pjsip/src/pjsip-ua/sip_siprec.c Outdated
Comment thread pjsip/src/pjsip-ua/sip_siprec.c Outdated
Comment on lines +2374 to +2376
/* Only process if SIPREC is supported */
if (!(inv->options & PJSIP_INV_SUPPORT_SIPREC))
return PJ_SUCCESS;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong flag. The doxygen for pjsip_siprec_verify_update() says the session must be SIPREC-enabled with PJSIP_INV_REQUIRE_SIPREC, and REQUIRE implies SUPPORT (see line 1365) — but not the reverse.

pjsua_call.c sets PJSIP_INV_SUPPORT_SIPREC on every incoming call whenever the account has use_siprec != PJSUA_SIP_SIPREC_INACTIVE, so ordinary non-recording calls run this path too. Combined with siprec_require_metadata = PJ_TRUE, every ordinary re-INVITE on such an account would be answered 400. Please test PJSIP_INV_REQUIRE_SIPREC.

Comment on lines +6034 to +6036
/* Process SIPREC metadata update if present */
if (inv_process_siprec_metadata_update(inv, rdata) != PJ_SUCCESS)
return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bare return here relies on the helper having sent the response, which it does not always do (see my comment on the helper's error path). inv->invite_tsx has already been assigned above, so on that path the re-INVITE is left unanswered until the transaction times out.

Please guarantee a final response before returning.

Comment on lines +6096 to +6100
call->siprec_metadata.ptr = (char*)
pj_pool_alloc(call->inv->pool_prov, new_metadata->slen);
pj_memcpy(call->siprec_metadata.ptr, new_metadata->ptr,
new_metadata->slen);
call->siprec_metadata.slen = new_metadata->slen;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use-after-free. pool_prov is the provisional flip-flop pool: inv_negotiate_sdp() swaps it and calls pj_pool_reset() on it after every negotiation (see the ticket #877 comment in sip_inv.h). This callback fires before negotiation in the same handler, so the copy is released within one or two re-INVITE rounds and the memory is then handed out to unrelated allocations.

Separately — call->siprec_metadata is write-only across the entire tree. Nothing reads it, there is no pjsua or pjsua2 accessor for it, and no pjsua_callback entry was added, so this whole hunk currently has no user-visible effect. Please either complete it (a pjsua-level callback plus an accessor, allocated from a pool with a suitable lifetime), or drop the pjsua part from this PR and keep the change at the pjsip-ua layer.

Comment on lines +272 to +273
#if PJSUA_HAS_SIPREC
inv_cb.on_siprec_metadata_update = &pjsua_call_on_siprec_metadata_update;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pjsua claims on_siprec_metadata_update unconditionally here, so an application built on pjsua can never install its own handler and never learns about the update. If the pjsua part stays in this PR, it needs a corresponding pjsua_callback entry to forward the event.

Comment on lines +383 to +401
#if PJSUA_HAS_SIPREC
/**
* This callback is called when SIPREC rs-metadata is updated via
* mid-dialog re-INVITE or UPDATE request. This allows applications
* to track metadata changes during the lifetime of a recording
* session, as required by RFC 7866.
*
* The callback is invoked after the metadata has been successfully
* parsed and stored in the INVITE session, but before SDP
* negotiation completes.
*
* This callback is optional.
*
* @param inv The invite session.
* @param old_metadata Previous metadata (may be NULL or empty).
* @param new_metadata New metadata from the update.
* @param rdata The received request containing the update.
*/
void (*on_siprec_metadata_update)(pjsip_inv_session *inv,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These #if PJSUA_HAS_SIPREC guards make the layout of public pjsip-ua structs (pjsip_inv_callback here, pjsip_inv_session below) depend on a PJSUA_* macro — a layering inversion, since pjsip-ua sits below pjsua-lib.

It happens to work today only because config_site.h is pulled in ahead of everything. Note that pjsua.h defines its own default for this macro after it has already included sip_inv.h, so defining PJSUA_HAS_SIPREC anywhere other than config_site.h would silently desynchronise these struct layouts between translation units. I'd prefer both fields unconditional.

Comment on lines +184 to +190
PJ_DECL(pj_status_t) pjsip_siprec_verify_update(pjsip_rx_data *rdata,
pj_str_t *metadata,
pj_pool_t *pool,
pjsip_tx_data **p_tdata,
pjsip_dialog *dlg,
pjsip_endpoint *endpt,
const pjsip_siprec_verify_setting *setting);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style: the continuation lines are indented one space past the open paren, and the last line is 94 columns. Please align the parameters with the opening paren and keep to ~80 columns (same for pjsip_siprec_parse_data_mode() below).

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.

SIPREC module improvements needed

2 participants