From 2ab7d4f5d5b9588e6dfec796a816bbab032e20a9 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 20 Sep 2024 12:15:51 -0400 Subject: [PATCH] MT#55283 delay SDP parsing until we have a call For trickle ICE updates that need to be queued up, this requires storing the unparsed SDP in the fragment object, and then doing the parsing when actually processing the fragment. This allows the call's memory arena to be used for parsing. Change-Id: I28ed192c4443cedfa3095007cc8a555e3aa7a17a --- daemon/call_interfaces.c | 29 +++++++++++++++++------------ daemon/ice.c | 35 ++++++++++++++++++++++++++--------- daemon/janus.c | 9 ++++++--- include/ice.h | 2 +- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 6d0bc83ef..3c9608c22 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -2159,15 +2159,11 @@ static const char *call_offer_answer_ng(ng_command_ctx_t *ctx, enum call_opmode goto out; } - errstr = "Incomplete SDP specification"; - if (sdp_streams(&parsed, &streams, &flags)) - goto out; - /* OP_ANSWER; OP_OFFER && !IS_FOREIGN_CALL */ call = call_get(&flags.call_id); // SDP fragments for trickle ICE must always operate on an existing call - if (opmode == OP_OFFER && trickle_ice_update(ctx->ngbuf, call, &flags, &streams)) { + if (opmode == OP_OFFER && trickle_ice_update(ctx->ngbuf, call, &flags, NULL, &parsed)) { errstr = NULL; // SDP fragments for trickle ICE are consumed with no replacement returned goto out; @@ -2190,6 +2186,10 @@ static const char *call_offer_answer_ng(ng_command_ctx_t *ctx, enum call_opmode if (!call) goto out; + errstr = "Incomplete SDP specification"; + if (sdp_streams(&parsed, &streams, &flags)) + goto out; + if (flags.debug) CALL_SET(call, DEBUG); @@ -3695,14 +3695,18 @@ const char *call_publish_ng(ng_command_ctx_t *ctx, if (sdp_parse(&sdp_in, &parsed, &flags)) return "Failed to parse SDP"; - if (sdp_streams(&parsed, &streams, &flags)) - return "Incomplete SDP specification"; - call = call_get_or_create(&flags.call_id, false); + call = call_get(&flags.call_id); - if (trickle_ice_update(ctx->ngbuf, call, &flags, &streams)) + if (trickle_ice_update(ctx->ngbuf, call, &flags, NULL, &parsed)) return NULL; + if (!call) + call = call_get_or_create(&flags.call_id, false); + + if (sdp_streams(&parsed, &streams, &flags)) + return "Incomplete SDP specification"; + updated_created_from(call, addr, sin); struct call_monologue *ml = call_get_or_create_monologue(call, &flags.from_tag); @@ -3854,7 +3858,10 @@ const char *call_subscribe_answer_ng(ng_command_ctx_t *ctx) { if (!call) return "Unknown call-ID"; - if (trickle_ice_update(ctx->ngbuf, call, &flags, &streams)) + if (sdp_parse(&flags.sdp, &parsed, &flags)) + return "Failed to parse SDP"; + + if (trickle_ice_update(ctx->ngbuf, call, &flags, NULL, &parsed)) return NULL; if (!flags.to_tag.s) @@ -3867,8 +3874,6 @@ const char *call_subscribe_answer_ng(ng_command_ctx_t *ctx) { if (!dest_ml) return "To-tag not found"; - if (sdp_parse(&flags.sdp, &parsed, &flags)) - return "Failed to parse SDP"; if (sdp_streams(&parsed, &streams, &flags)) return "Incomplete SDP specification"; diff --git a/daemon/ice.c b/daemon/ice.c index 56a7d4c0c..4b672c104 100644 --- a/daemon/ice.c +++ b/daemon/ice.c @@ -41,6 +41,7 @@ struct sdp_fragment { ng_buffer *ngbuf; struct timeval received; sdp_streams_q streams; + sdp_sessions_q sdp; sdp_ng_flags flags; }; @@ -101,7 +102,16 @@ static fragments_ht sdp_fragments; -static void ice_update_media_streams(struct call_monologue *ml, sdp_streams_q *streams) { +static void ice_update_media_streams(struct call_monologue *ml, sdp_streams_q *streams, sdp_sessions_q *sdp, + sdp_ng_flags *flags) +{ + if (!streams || !streams->head) { + if (sdp_streams(sdp, streams, flags)) { + ilogs(ice, LOG_WARN, "Incomplete SDP specification for tricle ICE"); + return; + } + } + for (__auto_type l = streams->head; l; l = l->next) { struct stream_params *sp = l->data; struct call_media *media = NULL; @@ -143,6 +153,7 @@ static int frag_key_eq(const struct fragment_key *a, const struct fragment_key * static void fragment_free(struct sdp_fragment *frag) { sdp_streams_clear(&frag->streams); + sdp_sessions_clear(&frag->sdp); call_ng_free_flags(&frag->flags); obj_put(frag->ngbuf); g_slice_free1(sizeof(*frag), frag); @@ -152,7 +163,7 @@ static void fragment_key_free(struct fragment_key *k) { g_free(k->from_tag.s); g_slice_free1(sizeof(*k), k); } -static void queue_sdp_fragment(ng_buffer *ngbuf, sdp_streams_q *streams, sdp_ng_flags *flags) { +static void queue_sdp_fragment(ng_buffer *ngbuf, sdp_streams_q *streams, sdp_sessions_q *sdp, sdp_ng_flags *flags) { ilog(LOG_DEBUG, "Queuing up SDP fragment for " STR_FORMAT_M "/" STR_FORMAT_M, STR_FMT_M(&flags->call_id), STR_FMT_M(&flags->from_tag)); @@ -163,9 +174,15 @@ static void queue_sdp_fragment(ng_buffer *ngbuf, sdp_streams_q *streams, sdp_ng_ struct sdp_fragment *frag = g_slice_alloc0(sizeof(*frag)); frag->received = rtpe_now; frag->ngbuf = obj_get(ngbuf); - frag->streams = *streams; + if (sdp) { + frag->sdp = *sdp; + t_queue_init(sdp); + } + if (streams) { + frag->streams = *streams; + t_queue_init(streams); + } frag->flags = *flags; - t_queue_init(streams); ZERO(*flags); mutex_lock(&sdp_fragments_lock); @@ -174,22 +191,22 @@ static void queue_sdp_fragment(ng_buffer *ngbuf, sdp_streams_q *streams, sdp_ng_ mutex_unlock(&sdp_fragments_lock); } bool trickle_ice_update(ng_buffer *ngbuf, call_t *call, sdp_ng_flags *flags, - sdp_streams_q *streams) + sdp_streams_q *streams, sdp_sessions_q *sdp) { if (!flags->fragment) return false; if (!call) { - queue_sdp_fragment(ngbuf, streams, flags); + queue_sdp_fragment(ngbuf, streams, sdp, flags); return true; } struct call_monologue *ml = call_get_monologue(call, &flags->from_tag); if (!ml) { - queue_sdp_fragment(ngbuf, streams, flags); + queue_sdp_fragment(ngbuf, streams, sdp, flags); return true; } - ice_update_media_streams(ml, streams); + ice_update_media_streams(ml, streams, sdp, flags); return true; } @@ -219,7 +236,7 @@ void dequeue_sdp_fragments(struct call_monologue *monologue) { ilog(LOG_DEBUG, "Dequeuing SDP fragment for " STR_FORMAT_M "/" STR_FORMAT_M, STR_FMT_M(&k.call_id), STR_FMT_M(&k.from_tag)); - ice_update_media_streams(monologue, &frag->streams); + ice_update_media_streams(monologue, &frag->streams, &frag->sdp, &frag->flags); next: fragment_free(frag); diff --git a/daemon/janus.c b/daemon/janus.c index dc4597fcf..a3334f40f 100644 --- a/daemon/janus.c +++ b/daemon/janus.c @@ -965,8 +965,6 @@ static const char *janus_videoroom_start(struct websocket_message *wm, struct ja *retcode = 512; if (sdp_parse(&sdp_in, &parsed, &flags)) return "Failed to parse SDP"; - if (sdp_streams(&parsed, &streams, &flags)) - return "Incomplete SDP specification"; struct janus_room *room = t_hash_table_lookup(janus_rooms, &room_id); *retcode = 426; @@ -975,6 +973,11 @@ static const char *janus_videoroom_start(struct websocket_message *wm, struct ja g_autoptr(call_t) call = call_get(&room->call_id); if (!call) return "No such room"; + + *retcode = 512; + if (sdp_streams(&parsed, &streams, &flags)) + return "Incomplete SDP specification"; + *retcode = 456; uint64_t *feed_id = t_hash_table_lookup(room->subscribers, &handle->id); if (!feed_id) @@ -1672,7 +1675,7 @@ static const char *janus_trickle(JsonReader *reader, struct janus_session *sessi bencode_strdup_str(&ngbuf->buffer, &sp->ice_ufrag, ufrag); // finally do the update - trickle_ice_update(ngbuf, call, &flags, &streams); + trickle_ice_update(ngbuf, call, &flags, &streams, NULL); return NULL; } diff --git a/include/ice.h b/include/ice.h index 638391090..c2e3a4fda 100644 --- a/include/ice.h +++ b/include/ice.h @@ -167,7 +167,7 @@ int ice_response(stream_fd *, const endpoint_t *src, void dequeue_sdp_fragments(struct call_monologue *); bool trickle_ice_update(ng_buffer *ngbuf, call_t *call, sdp_ng_flags *flags, - sdp_streams_q *streams); + sdp_streams_q *streams, sdp_sessions_q *sdp); enum thread_looper_action ice_slow_timer(void);