From 65e591bf99c46382068627617cfe599c06657132 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 31 Jul 2025 14:40:50 -0400 Subject: [PATCH] MT#63317 revamp SDP printing Change-Id: I0079cc8ec59a604048a11167cd576e49fc144a6a --- daemon/sdp.c | 441 +++++++++++++++++++++++++++++--------------------- include/sdp.h | 8 +- 2 files changed, 265 insertions(+), 184 deletions(-) diff --git a/daemon/sdp.c b/daemon/sdp.c index 44c9a32ac..af5784739 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -348,15 +348,6 @@ static bool sdp_manipulate_remove(const struct sdp_manipulations * sdp_manipulat return false; /* means don't remove */ } -/** - * Checks whether an attribute removal request exists for a given session level. - * `attr_name` must be without `a=`. - */ -static bool sdp_manipulate_remove_c(const char *attr_name, const sdp_ng_flags *flags, enum media_type media_type) { - struct sdp_manipulations *sdp_manipulations = sdp_manipulations_get_by_id(flags->sdp_manipulations, media_type); - return sdp_manipulate_remove(sdp_manipulations, STR_PTR(attr_name)); -} - /** * Adds values into a requested session level (global, audio, video) */ @@ -397,31 +388,112 @@ static str *sdp_manipulations_subst(const struct sdp_manipulations * sdp_manipul return cmd_subst_value; } -static void append_str_attr_to_gstring(GString *s, const str * name, const str * value, - const sdp_ng_flags *flags, enum media_type media_type); -static void append_attr_int_to_gstring(GString *s, const char * value, const int additional, + +__attribute__((nonnull(1, 2, 3, 4))) +static void append_str_attr_to_gstring(GString *s, const str *name, const str *value, const sdp_ng_flags *flags, enum media_type media_type); -static void append_tagged_attr_to_gstring(GString *s, const char * name, const str *tag, const str * value, +__attribute__((nonnull(1, 2, 3))) +static void append_null_str_attr_to_gstring(GString *s, const str *name, const sdp_ng_flags *flags, enum media_type media_type); -static void append_int_tagged_attr_to_gstring(GString *s, const char * name, unsigned int tag, const str * value, +__attribute__((nonnull(1, 2, 4, 5))) +static void append_int_tagged_str_attr_to_gstring(GString *s, const str *name, unsigned int tag, const str *value, const sdp_ng_flags *flags, enum media_type media_type); -void sdp_append_str_attr(GString *s, const sdp_ng_flags *flags, enum media_type media_type, - const str *name, const char *fmt, ...) -{ +#define append_int_tagged_attr_to_gstring(s, name, tag, value, flags, type) \ + append_int_tagged_str_attr_to_gstring(s, STR_PTR(name), tag, value, flags, type) +#define append_v_attr_to_gstring(s, name, flags, type, fmt, ...) \ + append_v_str_attr_to_gstring(s, STR_PTR(name), flags, type, fmt, ##__VA_ARGS__) +#define append_attr_int_to_gstring(s, name, value, flags, type) \ + append_v_attr_to_gstring(s, name, flags, type, "%u", value) +#define append_attr_to_gstring(s, name, value, flags, type) \ + append_str_attr_to_gstring(s, STR_PTR(name), value, flags, type) +#define append_null_attr_to_gstring(s, name, flags, type) \ + append_null_str_attr_to_gstring(s, STR_PTR(name), flags, type) +#define append_gen_attr_to_gstring(s, name, value, flags, type) ({ \ + if ((value)->len) \ + append_str_attr_to_gstring(s, name, value, flags, type); \ + else \ + append_null_str_attr_to_gstring(s, name, flags, type); \ + }) + +struct sdp_state { + GString *s; + size_t start; + struct sdp_manipulations *manip; + const sdp_ng_flags *flags; +}; + +// Records the current state of the output SDP and writes the attribute lead-in `a=` +static struct sdp_state __attr_begin(GString *s, const sdp_ng_flags *flags, enum media_type media_type) { + struct sdp_manipulations *manip = sdp_manipulations_get_by_id(flags->sdp_manipulations, media_type); + + g_string_append(s, "a="); + + return (struct sdp_state) { + .s = s, + .start = s->len, + .manip = manip, + .flags = flags, + }; +} + +static void __attr_end(const struct sdp_state *state) { + g_string_append(state->s, "\r\n"); +} + +// Checks for attribute removal or substitutions. +// If removal or substitution was done, returns true +static bool __attr_manip(const struct sdp_state *state) { + str attr = STR_LEN(state->s->str + state->start, state->s->len - state->start); + + /* first check if the originally present attribute is to be removed */ + if (sdp_manipulate_remove(state->manip, &attr)) { + // remove everything including the `a=` + g_string_truncate(state->s, state->start - 2); + return true; + } + + str *attr_subst = sdp_manipulations_subst(state->manip, &attr); + if (attr_subst) { + // rewind to `a=`, write complete attribute, and call it a day + g_string_truncate(state->s, state->start); + g_string_append_len(state->s, attr_subst->s, attr_subst->len); + __attr_end(state); + return true; + } + + // continue... + return false; +} + +/** + * Appends attribute fragment (`name` or `name:tag` or `value`) to the output SDP. + * Includes substitute and remove SDP attribute manipulations. + * Return true if attribute was substituted or removed. + */ +__attribute__((nonnull(1, 2))) +static bool __attr_append_str(const struct sdp_state *state, const str *s) { + g_string_append_len(state->s, s->s, s->len); + return __attr_manip(state); +} +#define __attr_append(state, s) __attr_append_str(state, STR_PTR(s)) +__attribute__((nonnull(1, 2))) +static bool __attr_append_v(const struct sdp_state *state, const char *fmt, va_list ap) { + g_string_append_vprintf(state->s, fmt, ap); + return __attr_manip(state); +} +__attribute__((format(printf, 2, 3))) +__attribute__((nonnull(1, 2))) +static bool __attr_append_f(const struct sdp_state *state, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - g_autoptr(GString) gs = g_string_new(""); - g_string_vprintf(gs, fmt, ap); + bool ret = __attr_append_v(state, fmt, ap); va_end(ap); - append_str_attr_to_gstring(s, name, &STR_GS(gs), flags, media_type); + return ret; } -INLINE void append_attr_to_gstring(GString *s, const char * name, const str * value, - const sdp_ng_flags *flags, enum media_type media_type) -{ - append_str_attr_to_gstring(s, STR_PTR(name), value, flags, media_type); -} + + INLINE struct sdp_attribute *attr_get_by_id(struct sdp_attributes *a, enum attr_id id) { return t_hash_table_lookup(a->id_hash, GINT_TO_POINTER(id)); } @@ -2120,7 +2192,7 @@ void sdp_insert_media_attributes(GString *gs, struct call_media *media, struct c __auto_type s = l->data; if (s->other == ATTR_OTHER_EXTMAP && flags->strip_extmap && !MEDIA_ISSET(source_media, PASSTHRU)) continue; - append_str_attr_to_gstring(gs, &s->strs.name, &s->strs.value, flags, source_media->type_id); + append_gen_attr_to_gstring(gs, &s->strs.name, &s->strs.value, flags, source_media->type_id); } } void sdp_insert_monologue_attributes(GString *gs, struct call_monologue *ml, const sdp_ng_flags *flags) { @@ -2135,7 +2207,7 @@ void sdp_insert_monologue_attributes(GString *gs, struct call_monologue *ml, con __auto_type s = l->data; if (s->other == ATTR_OTHER_EXTMAP && flags->strip_extmap) continue; - append_str_attr_to_gstring(gs, &s->strs.name, &s->strs.value, flags, MT_UNKNOWN); + append_gen_attr_to_gstring(gs, &s->strs.name, &s->strs.value, flags, MT_UNKNOWN); } } void sdp_insert_all_attributes(GString *s, struct call_media *media, struct sdp_ng_flags *flags) { @@ -2145,18 +2217,17 @@ void sdp_insert_all_attributes(GString *s, struct call_media *media, struct sdp_ // so that we can print our own candidates first if (a->attr == ATTR_END_OF_CANDIDATES) continue; - append_str_attr_to_gstring(s, &a->strs.name, &a->strs.value, flags, media->type_id); + append_gen_attr_to_gstring(s, &a->strs.name, &a->strs.value, flags, media->type_id); } } -static int insert_ice_address(GString *s, stream_fd *sfd, const sdp_ng_flags *flags) { +static bool insert_ice_address(const struct sdp_state *state, stream_fd *sfd, const sdp_ng_flags *flags) { if (!is_addr_unspecified(&flags->media_address)) - sockaddr_print_gstring(s, &flags->media_address); + sockaddr_print_gstring(state->s, &flags->media_address); else - call_stream_address(s, sfd->stream, SAF_ICE, sfd->local_intf, false); - g_string_append_printf(s, " %u", sfd->socket.local.port); - - return 0; + call_stream_address(state->s, sfd->stream, SAF_ICE, sfd->local_intf, false); + g_string_append_printf(state->s, " %u", sfd->socket.local.port); + return __attr_manip(state); } static int insert_raddr_rport(GString *s, stream_fd *sfd, const sdp_ng_flags *flags) { @@ -2216,22 +2287,36 @@ static void insert_candidate(GString *s, stream_fd *sfd, unsigned long priority; struct packet_stream *ps = sfd->stream; const struct local_intf *ifa = sfd->local_intf; - g_autoptr(GString) s_dst = g_string_new(""); + __auto_type state = __attr_begin(s, flags, (media ? media->type_id : MT_UNKNOWN)); + if (__attr_append(&state, "candidate")) + return; + g_string_append_c(s, ':'); + if (__attr_append_str(&state, &ifa->ice_foundation)) + return; if (local_pref == -1) local_pref = ifa->unique_id; priority = ice_priority_pref(type_pref, local_pref, ps->component); - g_string_append_printf(s_dst, "%u UDP %lu ", ps->component, priority); - insert_ice_address(s_dst, sfd, flags); - g_string_append(s_dst, " typ "); - g_string_append(s_dst, ice_candidate_type_str(type)); + if (__attr_append_f(&state, " %u", ps->component)) + return; + if (__attr_append(&state, " UDP")) + return; + if (__attr_append_f(&state, " %lu", priority)) + return; + g_string_append_c(s, ' '); + if (insert_ice_address(&state, sfd, flags)) + return; + g_string_append(s, " typ "); + g_string_append(s, ice_candidate_type_str(type)); + if (__attr_manip(&state)) + return; /* raddr and rport are required for non-host candidates: rfc5245 section-15.1 */ if(type != ICT_HOST) - insert_raddr_rport(s_dst, sfd, flags); - - append_tagged_attr_to_gstring(s, "candidate", &ifa->ice_foundation, &STR_GS(s_dst), flags, - (media ? media->type_id : MT_UNKNOWN)); + insert_raddr_rport(s, sfd, flags); + if (__attr_manip(&state)) + return; + __attr_end(&state); } static void insert_sfd_candidates(GString *s, struct packet_stream *ps, @@ -2247,6 +2332,26 @@ static void insert_sfd_candidates(GString *s, struct packet_stream *ps, } } +static void insert_remote_candidates(GString *s, const sdp_ng_flags *flags, struct call_media *media, struct ice_agent *ag) { + g_auto(candidate_q) rc = TYPED_GQUEUE_INIT; + __auto_type state = __attr_begin(s, flags, media->type_id); + if (__attr_append(&state, "remote-candidates")) + return; + g_string_append_c(s, ':'); + + /* prepare remote-candidates */ + ice_remote_candidates(&rc, ag); + for (__auto_type l = rc.head; l; l = l->next) { + if (l != rc.head) + g_string_append(s, " "); + __auto_type cand = l->data; + if (__attr_append_f(&state, "%lu %s %u", cand->component_id, + sockaddr_print_buf(&cand->endpoint.address), cand->endpoint.port)) + return; + } + __attr_end(&state); +} + static void insert_candidates(GString *s, struct packet_stream *rtp, struct packet_stream *rtcp, const sdp_ng_flags *flags, struct call_media *source_media) { @@ -2255,7 +2360,6 @@ static void insert_candidates(GString *s, struct packet_stream *rtp, struct pack struct ice_agent *ag; unsigned int type_pref, local_pref; enum ice_candidate_type cand_type; - struct ice_candidate *cand; media = rtp->media; @@ -2278,22 +2382,9 @@ static void insert_candidates(GString *s, struct packet_stream *rtp, struct pack insert_candidate(s, rtcp->selected_sfd, type_pref, ifa->unique_id, cand_type, flags, rtp->media); - if (flags->opmode == OP_OFFER && AGENT_ISSET(ag, CONTROLLING)) { - g_auto(candidate_q) rc = TYPED_GQUEUE_INIT; - g_autoptr(GString) s_dst = g_string_new(""); - - /* prepare remote-candidates */ - ice_remote_candidates(&rc, ag); - for (__auto_type l = rc.head; l; l = l->next) { - if (l != rc.head) - g_string_append(s_dst, " "); - cand = l->data; - g_string_append_printf(s_dst, "%lu %s %u", cand->component_id, - sockaddr_print_buf(&cand->endpoint.address), cand->endpoint.port); - } - append_attr_to_gstring(s, "remote-candidates", &STR_GS(s_dst), flags, - rtp->media->type_id); - } + if (flags->opmode == OP_OFFER && AGENT_ISSET(ag, CONTROLLING)) + insert_remote_candidates(s, flags, rtp->media, ag); + return; } @@ -2322,11 +2413,43 @@ static void insert_setup(GString *out, struct call_media *media, const sdp_ng_fl append_attr_to_gstring(out, "setup", &actpass_str, flags, media->type_id); } +static void insert_fingerprint(GString *s, struct call_media *media, const sdp_ng_flags *flags, + const struct dtls_hash_func *hf, struct dtls_fingerprint *fp) +{ + /* prepare fingerprint */ + __auto_type state = __attr_begin(s, flags, media->type_id); + if (__attr_append(&state, "fingerprint")) + return; + g_string_append_c(s, ':'); + if (__attr_append(&state, hf->name)) + return; + g_string_append(s, " "); + + unsigned char *p = fp->digest; + for (unsigned int i = 0; i < hf->num_bytes; i++) + g_string_append_printf(s, "%02X:", *p++); + g_string_truncate(s, s->len - 1); + + __attr_end(&state); +} + +static void insert_tls_id(GString *s, struct call_media *media, const sdp_ng_flags *flags, struct dtls_connection *dtls) { + /* prepare tls-id */ + __auto_type state = __attr_begin(s, flags, media->type_id); + if (__attr_append(&state, "tls-id")) + return; + g_string_append_c(s, ':'); + + unsigned char *p = dtls->tls_id; + for (unsigned int i = 0; i < sizeof(dtls->tls_id); i++) + g_string_append_printf(s, "%02x", *p++); + + __attr_end(&state); +} + static void insert_dtls(GString *s, struct call_media *media, struct dtls_connection *dtls, const sdp_ng_flags *flags) { - unsigned char *p; - int i; const struct dtls_hash_func *hf; call_t *call = media->call; @@ -2359,28 +2482,10 @@ static void insert_dtls(GString *s, struct call_media *media, struct dtls_connec /* a=setup: */ insert_setup(s, media, flags, true); - /* prepare fingerprint */ - g_autoptr(GString) s_dst = g_string_new(""); - g_string_append(s_dst, hf->name); - g_string_append(s_dst, " "); + insert_fingerprint(s, media, flags, hf, fp); - p = fp->digest; - for (i = 0; i < hf->num_bytes; i++) - g_string_append_printf(s_dst, "%02X:", *p++); - g_string_truncate(s_dst, s_dst->len - 1); - - append_attr_to_gstring(s, "fingerprint", &STR_GS(s_dst), flags, media->type_id); - - if (dtls) { - /* prepare tls-id */ - g_string_truncate(s_dst, 0); - - p = dtls->tls_id; - for (i = 0; i < sizeof(dtls->tls_id); i++) - g_string_append_printf(s_dst, "%02x", *p++); - - append_attr_to_gstring(s, "tls-id", &STR_GS(s_dst), flags, media->type_id); - } + if (dtls) + insert_tls_id(s, media, flags, dtls); } static void insert_crypto1(GString *s, struct call_media *media, struct crypto_params_sdes *cps, @@ -2394,7 +2499,16 @@ static void insert_crypto1(GString *s, struct call_media *media, struct crypto_p if (!cps->params.crypto_suite || !MEDIA_ISSET(media, SDES) || MEDIA_ISSET(media, PASSTHRU)) return; - g_autoptr(GString) s_dst = g_string_new(""); + __auto_type a_s = __attr_begin(s, flags, media->type_id); + if (__attr_append(&a_s, "crypto")) + return; + if (__attr_append_f(&a_s, ":%u", cps->tag)) + return; + g_string_append_c(s, ' '); + if (__attr_append(&a_s, cps->params.crypto_suite->name)) + return; + if (__attr_append(&a_s, " inline:")) + return; p = b64_buf; p += g_base64_encode_step((unsigned char *) cps->params.master_key, @@ -2411,26 +2525,25 @@ static void insert_crypto1(GString *s, struct call_media *media, struct crypto_p p--; } - g_string_append(s_dst, cps->params.crypto_suite->name); - g_string_append(s_dst, " inline:"); - g_string_append_len(s_dst, b64_buf, p - b64_buf); + if (__attr_append_str(&a_s, &STR_LEN(b64_buf, p - b64_buf))) + return; if (flags->sdes_lifetime) - g_string_append(s_dst, "|2^31"); + g_string_append(s, "|2^31"); if (cps->params.mki_len) { ull = 0; for (i = 0; i < cps->params.mki_len && i < sizeof(ull); i++) ull |= (unsigned long long) cps->params.mki[cps->params.mki_len - i - 1] << (i * 8); - g_string_append_printf(s_dst, "|%llu:%u", ull, cps->params.mki_len); + g_string_append_printf(s, "|%llu:%u", ull, cps->params.mki_len); } if (cps->params.session_params.unencrypted_srtp) - g_string_append(s_dst, " UNENCRYPTED_SRTP"); + g_string_append(s, " UNENCRYPTED_SRTP"); if (cps->params.session_params.unencrypted_srtcp) - g_string_append(s_dst, " UNENCRYPTED_SRTCP"); + g_string_append(s, " UNENCRYPTED_SRTCP"); if (cps->params.session_params.unauthenticated_srtp) - g_string_append(s_dst, " UNAUTHENTICATED_SRTP"); + g_string_append(s, " UNAUTHENTICATED_SRTP"); - append_int_tagged_attr_to_gstring(s, "crypto", cps->tag, &STR_GS(s_dst), flags, media->type_id); + __attr_end(&a_s); } static void insert_crypto(GString *s, struct call_media *media, const sdp_ng_flags *flags) { @@ -2444,20 +2557,24 @@ static void insert_rtcp_attr(GString *s, struct packet_stream *ps, const sdp_ng_ { if (flags->no_rtcp_attr) return; - g_autoptr(GString) s_dst = g_string_new(""); + __auto_type state = __attr_begin(s, flags, (media ? media->type_id : MT_UNKNOWN)); + if (__attr_append(&state, "rtcp")) + return; + g_string_append_c(s, ':'); - g_string_append_printf(s_dst, "%u", ps->selected_sfd->socket.local.port); + if (__attr_append_f(&state, "%u", ps->selected_sfd->socket.local.port)) + return; if (flags->full_rtcp_attr) { - g_string_append(s_dst, " IN "); + g_string_append(s, " IN "); if (!is_addr_unspecified(&flags->media_address)) - g_string_append_printf(s_dst, "%s %s", + g_string_append_printf(s, "%s %s", flags->media_address.family->rfc_name, sockaddr_print_buf(&flags->media_address)); else - call_stream_address(s_dst, ps, SAF_NG, NULL, false); + call_stream_address(s, ps, SAF_NG, NULL, false); } - append_attr_to_gstring(s, "rtcp", &STR_GS(s_dst), flags, (media ? media->type_id : MT_UNKNOWN)); + __attr_end(&state); } /** @@ -2544,95 +2661,59 @@ const char *sdp_get_sendrecv(struct call_media *media) { return "inactive"; } -/** - * Appends attributes to the output SDP. - * Includes substitute and remove SDP attribute manipulations. - */ -static void generic_append_attr_to_gstring(GString *s, const str * attr, char separator, const str * value, +/* Appends attributes (`a=name:value`) to the output SDP */ +static void append_str_attr_to_gstring(GString *s, const str *name, const str *value, const sdp_ng_flags *flags, enum media_type media_type) { - struct sdp_manipulations *sdp_manipulations = sdp_manipulations_get_by_id(flags->sdp_manipulations, media_type); - - str * attr_subst = sdp_manipulations_subst(sdp_manipulations, attr); - - /* first check if the originally present attribute is to be removed */ - if (sdp_manipulate_remove(sdp_manipulations, attr)) + __auto_type state = __attr_begin(s, flags, media_type); + if (__attr_append_str(&state, name)) return; - - g_string_append(s, "a="); - - /* then, if there remains something to be substituted, do that */ - if (attr_subst) - g_string_append_len(s, attr_subst->s, attr_subst->len); // complete attribute - else { - gsize attr_start = s->len; // save beginning of complete attribute string - - /* attr name */ - g_string_append_len(s, attr->s, attr->len); - - /* attr value */ - if (value && value->len) { - g_string_append_c(s, separator); - g_string_append_len(s, value->s, value->len); - - // check if the complete attribute string is marked for removal ... - str complete = STR_LEN(s->str + attr_start, s->len - attr_start); - if (sdp_manipulate_remove(sdp_manipulations, &complete)) - { - // rewind and bail - g_string_truncate(s, attr_start - 2); // -2 for `a=` - return; - } - - // ... or substitution - attr_subst = sdp_manipulations_subst(sdp_manipulations, &complete); - if (attr_subst) { - // rewind and replace - g_string_truncate(s, attr_start); - g_string_append_len(s, attr_subst->s, attr_subst->len); - } - } - } - - g_string_append(s, "\r\n"); + g_string_append_c(s, ':'); + if (__attr_append_str(&state, value)) + return; + __attr_end(&state); } -/* Appends attributes (`a=name:value`) to the output SDP */ -static void append_str_attr_to_gstring(GString *s, const str * name, const str * value, +/* Appends attributes (`a=name`) to the output SDP */ +static void append_null_str_attr_to_gstring(GString *s, const str *name, const sdp_ng_flags *flags, enum media_type media_type) { - generic_append_attr_to_gstring(s, name, ':', value, flags, media_type); + __auto_type state = __attr_begin(s, flags, media_type); + if (__attr_append_str(&state, name)) + return; + __attr_end(&state); } -/* Appends attributes (`a=name:tag value`) to the output SDP */ -static void append_tagged_attr_to_gstring(GString *s, const char * name, const str *tag, const str * value, - const sdp_ng_flags *flags, enum media_type media_type) +/* Appends attributes (`a=name:something`) to the output SDP */ +void append_v_str_attr_to_gstring(GString *s, const str *name, const sdp_ng_flags *flags, + enum media_type media_type, const char *fmt, ...) { - if (sdp_manipulate_remove_c(name, flags, media_type)) + __auto_type state = __attr_begin(s, flags, media_type); + if (__attr_append_str(&state, name)) + return; + g_string_append_c(s, ':'); + va_list ap; + va_start(ap, fmt); + bool ret = __attr_append_v(&state, fmt, ap); + va_end(ap); + if (ret) return; - g_autoptr(GString) n = g_string_new(name); - g_string_append_c(n, ':'); - g_string_append_len(n, tag->s, tag->len); - generic_append_attr_to_gstring(s, &STR_GS(n), ' ', value, flags, media_type); + __attr_end(&state); } /* Appends attributes (`a=name:uint value`) to the output SDP */ -static void append_int_tagged_attr_to_gstring(GString *s, const char * name, unsigned int tag, const str * value, +static void append_int_tagged_str_attr_to_gstring(GString *s, const str *name, unsigned int tag, const str *value, const sdp_ng_flags *flags, enum media_type media_type) { - if (sdp_manipulate_remove_c(name, flags, media_type)) + __auto_type state = __attr_begin(s, flags, media_type); + if (__attr_append_str(&state, name)) return; - g_autoptr(GString) n = g_string_new(name); - g_string_append_printf(n, ":%u", tag); - generic_append_attr_to_gstring(s, &STR_GS(n), ' ', value, flags, media_type); -} - -/* Appends attributes to the output SDP */ -static void append_attr_int_to_gstring(GString *s, const char * name, const int value, - const sdp_ng_flags *flags, enum media_type media_type) -{ - - append_int_tagged_attr_to_gstring(s, name, value, NULL, flags, media_type); + if (__attr_append_f(&state, ":%u", tag)) + return; + g_string_append_c(s, ' '); + if (__attr_append_str(&state, value)) + return; + __attr_end(&state); } static struct packet_stream *print_rtcp(GString *s, struct call_media *media, packet_stream_list *rtp_ps_link, @@ -2657,14 +2738,14 @@ static struct packet_stream *print_rtcp(GString *s, struct call_media *media, pa IS_OP_OTHER(flags->opmode))) { insert_rtcp_attr(s, ps, flags, media); - append_attr_to_gstring(s, "rtcp-mux", NULL, flags, media->type_id); + append_null_attr_to_gstring(s, "rtcp-mux", flags, media->type_id); ps_rtcp = NULL; } else if (ps_rtcp && flags->ice_option != ICE_FORCE_RELAY) { insert_rtcp_attr(s, ps_rtcp, flags, media); if (MEDIA_ISSET(media, RTCP_MUX)) - append_attr_to_gstring(s, "rtcp-mux", NULL, flags, media->type_id); + append_null_attr_to_gstring(s, "rtcp-mux", flags, media->type_id); } } else @@ -2739,15 +2820,15 @@ static void print_sdp_media_section(GString *s, struct call_media *media, { /* answer must be recvonly (sendonly-to-recvonly) */ if (MEDIA_ISSET(source_media, REAL_SENDONLY)) - append_attr_to_gstring(s, "recvonly", NULL, flags, media->type_id); + append_null_attr_to_gstring(s, "recvonly", flags, media->type_id); /* answer must be inactive (inactive-to-inactive) */ else - append_attr_to_gstring(s, "inactive", NULL, flags, media->type_id); + append_null_attr_to_gstring(s, "inactive", flags, media->type_id); /* clear flags for this MoH offer/answer exchange, so that future exchanges are real */ MEDIA_CLEAR(source_media, FAKE_SENDRECV); MEDIA_CLEAR(source_media, REAL_SENDONLY); } else { - append_attr_to_gstring(s, sdp_get_sendrecv(media), NULL, flags, + append_null_attr_to_gstring(s, sdp_get_sendrecv(media), flags, media->type_id); } } @@ -2782,7 +2863,7 @@ static void print_sdp_media_section(GString *s, struct call_media *media, } if ((MEDIA_ISSET(media, TRICKLE_ICE) && media->ice_agent)) { - append_attr_to_gstring(s, "end-of-candidates", NULL, flags, media->type_id); + append_null_attr_to_gstring(s, "end-of-candidates", flags, media->type_id); } return; @@ -2889,12 +2970,12 @@ static void sdp_out_add_other(GString *out, struct call_monologue *monologue, append_attr_to_gstring(out, "rtpengine", &rtpe_instance_id, flags, media->type_id); #ifdef WITH_TRANSCODING if (monologue->player && monologue->player->opts.moh && rtpe_config.moh_attr_name) { - append_attr_to_gstring(out, rtpe_config.moh_attr_name, NULL, flags, media->type_id); + append_null_attr_to_gstring(out, rtpe_config.moh_attr_name, flags, media->type_id); } #endif /* ice-lite */ if (media_has_ice && media_has_ice_lite_self) - append_attr_to_gstring(out, "ice-lite", NULL, flags, media->type_id); + append_null_attr_to_gstring(out, "ice-lite", flags, media->type_id); /* group */ if (source_ml && source_ml->sdp_session_group.len && flags->ice_option == ICE_FORCE_RELAY) @@ -3081,7 +3162,7 @@ static void sdp_out_original_media_attributes(GString *out, struct call_media *m rtcp_ps = NULL; insert_candidates(out, rtp_ps, rtcp_ps, flags, source_media); if (MEDIA_ISSET(source_media, END_OF_CANDIDATES)) - append_attr_to_gstring(out, "end-of-candidates", NULL, flags, media->type_id); + append_null_attr_to_gstring(out, "end-of-candidates", flags, media->type_id); } } diff --git a/include/sdp.h b/include/sdp.h index 84f699396..3ac9c473b 100644 --- a/include/sdp.h +++ b/include/sdp.h @@ -35,10 +35,10 @@ void sdp_init(void); void sdp_insert_media_attributes(GString *, struct call_media *, struct call_media *, const sdp_ng_flags *); void sdp_insert_monologue_attributes(GString *, struct call_monologue *, const sdp_ng_flags *); -void sdp_append_str_attr(GString *s, const sdp_ng_flags *flags, enum media_type media_type, - const str *name, const char *fmt, ...) - __attribute__ ((format (printf, 5, 6))); -#define sdp_append_attr(s, g, t, n, f, ...) sdp_append_str_attr(s, g, t, STR_PTR(n), f, ##__VA_ARGS__) +__attribute__((nonnull(1, 2, 3, 5))) +void append_v_str_attr_to_gstring(GString *s, const str *name, const sdp_ng_flags *flags, + enum media_type media_type, const char *fmt, ...); +#define sdp_append_attr(s, g, t, n, f, ...) append_v_str_attr_to_gstring(s, STR_PTR(n), g, t, f, ##__VA_ARGS__) void sdp_attr_free(struct sdp_attr *); sdp_origin *sdp_orig_dup(const sdp_origin *orig);