Skip to content

Commit 4c6c1c6

Browse files
committed
Also update local calls with new crypto params
1 parent b768bc4 commit 4c6c1c6

File tree

3 files changed

+255
-57
lines changed

3 files changed

+255
-57
lines changed

daemon/redis-json.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,64 @@ static redis_call_media_tag_t *redis_call_media_tag_create(unsigned unique_id, J
225225
return tagref;
226226
}
227227

228+
static void redis_call_media_sdes_free(void *rcms) {
229+
redis_call_media_sdes_t *sdesref = rcms;
230+
if (!sdesref)
231+
return;
232+
if (sdesref->crypto_suite_name)
233+
free(sdesref->crypto_suite_name);
234+
if (sdesref->master_key)
235+
free(sdesref->master_key);
236+
if (sdesref->master_salt)
237+
free(sdesref->master_salt);
238+
if (sdesref->mki)
239+
free(sdesref->mki);
240+
}
241+
242+
static redis_call_media_sdes_t *redis_call_media_sdes_create(const char *prefix, JsonObject* json) {
243+
redis_call_media_sdes_t *sdesref;
244+
str *fieldname;
245+
246+
sdesref = obj_alloc0("redis_call_media_sdes", sizeof(*sdesref), redis_call_media_sdes_free);
247+
fieldname = str_sprintf("%s_tag", prefix);
248+
JSON_UPDATE_NUM_FIELD_IF_SET_OR_FAIL(json, fieldname->s, sdesref->tag);
249+
free(fieldname);
250+
fieldname = str_sprintf("%s-crypto_suite", prefix);
251+
sdesref->crypto_suite_name = json_object_get_str(json, fieldname->s);
252+
free(fieldname);
253+
fieldname = str_sprintf("%s-master_key", prefix);
254+
sdesref->master_key = json_object_get_str_uri_enc(json, fieldname->s);
255+
free(fieldname);
256+
fieldname = str_sprintf("%s-master_salt", prefix);
257+
sdesref->master_salt = json_object_get_str_uri_enc(json, fieldname->s);
258+
free(fieldname);
259+
fieldname = str_sprintf("%s-mki", prefix);
260+
sdesref->mki = json_object_get_str(json, fieldname->s);
261+
free(fieldname);
262+
fieldname = str_sprintf("%s-unenc-srtp", prefix);
263+
JSON_UPDATE_NUM_FIELD_IF_SET(json, fieldname->s, sdesref->session_params.unencrypted_srtp);
264+
free(fieldname);
265+
fieldname = str_sprintf("%s-unenc-srtcp", prefix);
266+
JSON_UPDATE_NUM_FIELD_IF_SET(json, fieldname->s, sdesref->session_params.unencrypted_srtcp);
267+
free(fieldname);
268+
fieldname = str_sprintf("%s-unauth-srtp", prefix);
269+
JSON_UPDATE_NUM_FIELD_IF_SET(json, fieldname->s, sdesref->session_params.unauthenticated_srtp);
270+
271+
goto done;
272+
273+
fail:
274+
ilog(LOG_WARNING, "Failed to read crypto params %s from Redis", prefix);
275+
if (sdesref) {
276+
obj_put(sdesref);
277+
sdesref = NULL;
278+
}
279+
280+
done:
281+
if (fieldname)
282+
free(fieldname);
283+
return sdesref;
284+
}
285+
228286
static void redis_call_media_free(void* rcm) {
229287
redis_call_media_t *mediaref = rcm;
230288
if (!mediaref)
@@ -249,6 +307,14 @@ static void redis_call_media_free(void* rcm) {
249307
g_queue_free_full(mediaref->codec_prefs_recv, gdestroy_obj_put);
250308
if (mediaref->codec_prefs_send)
251309
g_queue_free_full(mediaref->codec_prefs_send, gdestroy_obj_put);
310+
if (mediaref->sdes_in)
311+
g_queue_free_full(mediaref->sdes_in, gdestroy_obj_put);
312+
if (mediaref->sdes_out)
313+
g_queue_free_full(mediaref->sdes_out, gdestroy_obj_put);
314+
if (mediaref->fingerprint.hash_func_name)
315+
free(mediaref->fingerprint.hash_func_name);
316+
if (mediaref->fingerprint.fingerprint)
317+
free(mediaref->fingerprint.fingerprint);
252318
}
253319

254320
static GQueue *redis_call_media_read_payloads(JsonArray* payload_types) {
@@ -303,6 +369,51 @@ static GQueue *redis_call_media_read_payloads(JsonArray* payload_types) {
303369
return out;
304370
}
305371

372+
static GQueue* redis_call_media_try_read_sdes(const char* prefix, JsonObject *json) {
373+
/* unlike all the other shit not-really-JSON that redis.c pulls, this time it encodes a list of items into the media
374+
* object itself, where the list index is encoded as "-%u" between the "type prefix" and the field name - but only
375+
* if its the second or later element. That code is fscking insane */
376+
GQueue *out = NULL;
377+
redis_call_media_sdes_t *sdesref = NULL;
378+
str *testfield = NULL;
379+
int idx;
380+
381+
/* check if we have any sdes for prefix */
382+
testfield = str_sprintf("%s_tag", prefix);
383+
if (!json_object_has_member(json, testfield->s))
384+
goto done; /* nope */
385+
386+
out = g_queue_new();
387+
sdesref = redis_call_media_sdes_create(prefix, json);
388+
if (!sdesref) { /* shouldn't happen, because we tested, but JSON might be broken */
389+
ilog(LOG_WARNING, "crypto params %s are broken", prefix);
390+
goto fail;
391+
}
392+
393+
g_queue_push_tail(out, sdesref);
394+
for (idx = 1; ; idx++) {
395+
free(testfield);
396+
testfield = str_sprintf("%s-%u", prefix, idx);
397+
sdesref = redis_call_media_sdes_create(testfield->s, json);
398+
if (!sdesref) /* no more crypto params */
399+
break;
400+
g_queue_push_tail(out, sdesref);
401+
}
402+
403+
goto done;
404+
405+
fail:
406+
if (out) {
407+
g_queue_free_full(out, gdestroy_obj_put);
408+
out = NULL;
409+
}
410+
411+
done:
412+
if (testfield)
413+
free(testfield);
414+
return out;
415+
}
416+
306417
static redis_call_media_t *redis_call_media_create(unsigned unique_id, JsonObject *json, GQueue *tags, GQueue *streams,
307418
JsonArray *stream_ids_ar, GQueue* endpoint_maps, JsonArray *endpoint_maps_ar, JsonArray *payload_types_recv_ar,
308419
JsonArray *payload_types_send_ar) {
@@ -334,6 +445,14 @@ static redis_call_media_t *redis_call_media_create(unsigned unique_id, JsonObjec
334445
JSON_UPDATE_NUM_FIELD_IF_SET(json, "media_flags", mediaref->media_flags);
335446
mediaref->rtpe_addr = json_object_get_str(json, "rtpe_addr");
336447

448+
/* try to read crypto params, if exist */
449+
mediaref->sdes_in = redis_call_media_try_read_sdes("sdes_in", json); /* we get NULL on failure, which is what we want */
450+
mediaref->sdes_out = redis_call_media_try_read_sdes("sdes_out", json);
451+
if (json_object_has_member(json, "hash_func")) {
452+
mediaref->fingerprint.hash_func_name = json_object_get_str(json, "hash_func");
453+
mediaref->fingerprint.fingerprint = json_object_get_str_uri_enc(json, "fingerprint");
454+
}
455+
337456
/* grab my streams */
338457
mediaref->streams = g_queue_new();
339458
for (idx = 0; idx < g_queue_get_length(streams); idx++) {

daemon/redis.c

Lines changed: 117 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,75 +1773,139 @@ static void redis_update_call_codec_handlers(struct call_media *media) {
17731773
}
17741774
}
17751775

1776-
static int redis_update_call_payloads(struct call *c, redis_call_t *redis_call) {
1777-
unsigned updated = 0, media_updates = 0;
1778-
struct call_media *m = NULL;
1779-
redis_call_media_t *media;
1776+
static int redis_update_call_payloads(struct call_media *m, redis_call_media_t *media) {
1777+
unsigned updated = 0;
1778+
1779+
/* replace codec prefs with those loaded from the database. */
1780+
/* TODO: ATM the database does not encode them correctly, so we lose some data. */
1781+
/* maybe convert codec prefs cleanup code to use __delete_x_codec (which is currently static) */
1782+
if (g_queue_get_length(media->codec_prefs_recv) != g_queue_get_length(&m->codecs_prefs_recv)) {
1783+
rlog(LOG_INFO, "['" STR_FORMAT_M "'] media %u: replacing %d local codec prefs recv with %d remote codec prefs",
1784+
STR_FMT_M(&m->call->callid), m->unique_id, g_queue_get_length(&m->codecs_prefs_recv),
1785+
g_queue_get_length(media->codec_prefs_recv));
1786+
g_hash_table_remove_all(m->codecs_recv);
1787+
g_hash_table_remove_all(m->codec_names_recv);
1788+
g_queue_clear_full(&m->codecs_prefs_recv, (GDestroyNotify) payload_type_free);
1789+
updated += redis_update_call_media_codecs(m, media->codec_prefs_recv, __rtp_payload_type_add_recv);
1790+
}
1791+
if (g_queue_get_length(media->codec_prefs_send) != g_queue_get_length(&m->codecs_prefs_send)) {
1792+
rlog(LOG_INFO, "['" STR_FORMAT_M "'] media %u: replacing %d local codec prefs send with %d remote codec prefs",
1793+
STR_FMT_M(&m->call->callid), m->unique_id, g_queue_get_length(&m->codecs_prefs_send),
1794+
g_queue_get_length(media->codec_prefs_send));
1795+
g_hash_table_remove_all(m->codecs_send);
1796+
g_hash_table_remove_all(m->codec_names_send);
1797+
g_queue_clear_full(&m->codecs_prefs_send, (GDestroyNotify) payload_type_free);
1798+
updated += redis_update_call_media_codecs(m, media->codec_prefs_send, __rtp_payload_type_add_send);
1799+
}
1800+
if (updated) {
1801+
redis_update_call_codec_handlers(m);
1802+
rlog(LOG_INFO, "Updated media %u codecs from Redis", m->unique_id);
1803+
}
1804+
return 0;
1805+
}
17801806

1781-
GList *l;
1782-
for (l = c->medias.head; l; l = l->next) {
1783-
m = l->data;
1784-
media = g_queue_peek_nth(redis_call->media, m->unique_id);
1785-
if (!media)
1786-
continue; /* weird... */
1787-
media_updates = updated;
1788-
/* replace codec prefs with those loaded from the database. */
1789-
/* TODO: ATM the database does not encode them correctly, so we lose some data. */
1790-
/* maybe convert codec prefs cleanup code to use __delete_x_codec (which is currently static) */
1791-
if (g_queue_get_length(media->codec_prefs_recv) != g_queue_get_length(&m->codecs_prefs_recv)) {
1792-
rlog(LOG_DEBUG, "['" STR_FORMAT_M "'] media %u: replacing %d local codec prefs recv with %d remote codec prefs",
1793-
STR_FMT_M(&c->callid), m->unique_id, g_queue_get_length(&m->codecs_prefs_recv),
1794-
g_queue_get_length(media->codec_prefs_recv));
1795-
g_hash_table_remove_all(m->codecs_recv);
1796-
g_hash_table_remove_all(m->codec_names_recv);
1797-
g_queue_clear_full(&m->codecs_prefs_recv, (GDestroyNotify) payload_type_free);
1798-
updated += redis_update_call_media_codecs(m, media->codec_prefs_recv, __rtp_payload_type_add_recv);
1807+
static int redis_update_call_maps(struct call_media *m, redis_call_media_t *media) {
1808+
struct endpoint_map *ep;
1809+
redis_call_media_endpoint_map_t *rcep;
1810+
GList *epl, *rcepl;
1811+
1812+
for (epl = m->endpoint_maps.head; epl; epl = epl->next) {
1813+
ep = epl->data;
1814+
for (rcepl = media->endpoint_maps->head; rcepl; rcepl = rcepl->next) {
1815+
rcep = rcepl->data;
1816+
if (rcep->unique_id != ep->unique_id)
1817+
continue;
1818+
ep->wildcard = rcep->wildcard;
1819+
endpoint_parse_any(&ep->endpoint, rcep->endpoint->s);
17991820
}
1800-
if (g_queue_get_length(media->codec_prefs_send) != g_queue_get_length(&m->codecs_prefs_send)) {
1801-
rlog(LOG_DEBUG, "['" STR_FORMAT_M "'] media %u: replacing %d local codec prefs send with %d remote codec prefs",
1802-
STR_FMT_M(&c->callid), m->unique_id, g_queue_get_length(&m->codecs_prefs_send),
1803-
g_queue_get_length(media->codec_prefs_send));
1804-
g_hash_table_remove_all(m->codecs_send);
1805-
g_hash_table_remove_all(m->codec_names_send);
1806-
g_queue_clear_full(&m->codecs_prefs_send, (GDestroyNotify) payload_type_free);
1807-
updated += redis_update_call_media_codecs(m, media->codec_prefs_send, __rtp_payload_type_add_send);
1821+
}
1822+
/* update some media fields here, while we have the media */
1823+
if (!m->ptime)
1824+
m->ptime = media->ptime;
1825+
m->media_flags = media->media_flags;
1826+
return 0;
1827+
}
1828+
1829+
static void redis_update_call_crypto_sync_sdes_params(GQueue *m_sdes_q, GQueue *redis_sdes_q) {
1830+
redis_call_media_sdes_t *redis_sdes;
1831+
1832+
crypto_params_sdes_queue_clear(m_sdes_q);
1833+
for (GList *l = redis_sdes_q->head; l; l = l->next) {
1834+
redis_sdes = l->data;
1835+
/** copied and modified from sdp.c:sdp_streams() */
1836+
struct crypto_params_sdes *cps = g_slice_alloc0(sizeof(*cps));
1837+
g_queue_push_tail(m_sdes_q, cps);
1838+
1839+
if (redis_sdes->crypto_suite_name)
1840+
cps->params.crypto_suite = crypto_find_suite(redis_sdes->crypto_suite_name);
1841+
if (redis_sdes->mki) {
1842+
cps->params.mki_len = redis_sdes->mki->len;
1843+
if (cps->params.mki_len) {
1844+
cps->params.mki = malloc(cps->params.mki_len);
1845+
memcpy(cps->params.mki, redis_sdes->mki->s, cps->params.mki_len);
1846+
}
18081847
}
1809-
if (updated != media_updates) {
1810-
redis_update_call_codec_handlers(m);
1848+
cps->tag = redis_sdes->tag;
1849+
if (redis_sdes->master_key)
1850+
memcpy(cps->params.master_key, redis_sdes->master_key->s, redis_sdes->master_key->len);
1851+
if (redis_sdes->master_salt)
1852+
memcpy(cps->params.master_salt, redis_sdes->master_salt->s, redis_sdes->master_salt->len);
1853+
cps->params.session_params = redis_sdes->session_params;
1854+
}
1855+
}
1856+
1857+
static int redis_update_call_crypto(struct call_media *m, redis_call_media_t *media) {
1858+
const struct dtls_hash_func *found_hash_func;
1859+
1860+
if (media->fingerprint.hash_func_name && !m->fingerprint.hash_func) {
1861+
/* json_restore_call() doesn't do this - should we? */
1862+
found_hash_func = dtls_find_hash_func(media->fingerprint.hash_func_name);
1863+
if (found_hash_func) {
1864+
rlog(LOG_DEBUG, "Updating crypto for call ID '" STR_FORMAT_M "', media %u from Redis",
1865+
STR_FMT_M(&m->call->callid), m->unique_id);
1866+
m->fingerprint.hash_func = found_hash_func;
1867+
memcpy(m->fingerprint.digest, media->fingerprint.fingerprint->s, media->fingerprint.fingerprint->len);
18111868
}
18121869
}
1813-
if (updated)
1814-
rlog(LOG_INFO, "Updated media codecs from Redis");
1870+
1871+
if (media->sdes_in && m->sdes_in.length != media->sdes_in->length)
1872+
redis_update_call_crypto_sync_sdes_params(&m->sdes_in, media->sdes_in);
1873+
if (media->sdes_out && m->sdes_out.length != media->sdes_out->length)
1874+
redis_update_call_crypto_sync_sdes_params(&m->sdes_in, media->sdes_in);
1875+
18151876
return 0;
18161877
}
18171878

1818-
static int redis_update_call_maps(struct call *c, redis_call_t *redis_call) {
1879+
static int redis_update_call_media(struct call *c, redis_call_t* redis_call) {
18191880
struct call_media *m = NULL;
1820-
struct endpoint_map *ep;
18211881
redis_call_media_t *media;
1822-
redis_call_media_endpoint_map_t *rcep;
1823-
GList *ml, *epl, *rcepl;
1882+
GList *ml;
18241883

18251884
for (ml = c->medias.head; ml; ml = ml->next) {
18261885
m = ml->data;
18271886
media = g_queue_peek_nth(redis_call->media, m->unique_id);
1828-
if (!media)
1887+
if (!media) {
1888+
rlog(LOG_WARNING, "Failed to update data for call ID '" STR_FORMAT_M "' from Redis: missing media %u",
1889+
STR_FMT_M(&c->callid), m->unique_id);
18291890
continue; /* weird... */
1830-
for (epl = m->endpoint_maps.head; epl; epl = epl->next) {
1831-
ep = epl->data;
1832-
for (rcepl = media->endpoint_maps->head; rcepl; rcepl = rcepl->next) {
1833-
rcep = rcepl->data;
1834-
if (rcep->unique_id != ep->unique_id)
1835-
continue;
1836-
ep->wildcard = rcep->wildcard;
1837-
endpoint_parse_any(&ep->endpoint, rcep->endpoint->s);
1838-
}
18391891
}
1840-
/* update some media fields here, while we have the media */
1841-
if (!m->ptime)
1842-
m->ptime = media->ptime;
1843-
m->media_flags = media->media_flags;
1892+
if (redis_update_call_maps(m, media)) {
1893+
rlog(LOG_WARNING, "Failed to update data for call ID '" STR_FORMAT_M "' from Redis: error in update maps",
1894+
STR_FMT_M(&c->callid));
1895+
return -1;
1896+
}
1897+
if (redis_update_call_payloads(m, media)) {
1898+
rlog(LOG_WARNING, "Failed to update data for call ID '" STR_FORMAT_M "' from Redis: error in update payloads",
1899+
STR_FMT_M(&c->callid));
1900+
return -1;
1901+
}
1902+
if (redis_update_call_crypto(m, media)) {
1903+
rlog(LOG_WARNING, "Failed to update data for call ID '" STR_FORMAT_M "' from Redis: error in update crypto",
1904+
STR_FMT_M(&c->callid));
1905+
return -1;
1906+
}
18441907
}
1908+
18451909
return 0;
18461910
}
18471911

@@ -1880,12 +1944,8 @@ static void redis_update_call_details(struct redis *r, struct call *c) {
18801944
if (redis_update_call_tags(c, redis_call))
18811945
goto fail;
18821946

1883-
err = "failed to update maps";
1884-
if (redis_update_call_maps(c, redis_call))
1885-
goto fail;
1886-
18871947
err = "failed to update payload data";
1888-
if (redis_update_call_payloads(c, redis_call))
1948+
if (redis_update_call_media(c, redis_call))
18891949
goto fail;
18901950

18911951
goto done;

include/redis-json.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "obj.h"
88
#include "str.h"
9+
#include "crypto.h"
910

1011
/**
1112
* Document object model for mapping call data to storable JSON.
@@ -80,6 +81,21 @@ typedef struct redis_call_media_tag {
8081
struct redis_call_media_tag* other_tag;
8182
} redis_call_media_tag_t;
8283

84+
typedef struct redis_call_media_sdes {
85+
struct obj obj;
86+
str* crypto_suite_name;
87+
str* master_key;
88+
str* master_salt;
89+
str* mki;
90+
struct crypto_session_params session_params;
91+
unsigned tag;
92+
} redis_call_media_sdes_t;
93+
94+
struct redis_call_media_fingerprint {
95+
str* hash_func_name;
96+
str* fingerprint;
97+
};
98+
8399
typedef struct redis_call_media {
84100
struct obj obj;
85101
unsigned index;
@@ -96,6 +112,9 @@ typedef struct redis_call_media {
96112
GQueue* streams; /**< list of redis_call_media_stream_t */
97113
GQueue* codec_prefs_recv; /**< list of redis_call_rtp_payload_type_t */
98114
GQueue* codec_prefs_send; /**< list of redis_call_rtp_payload_type_t */
115+
GQueue* sdes_in; /**< list of redis_call_media_sdes_t */
116+
GQueue* sdes_out; /**< list of redis_call_media_sdes_t */
117+
struct redis_call_media_fingerprint fingerprint; /* not an object reference */
99118
} redis_call_media_t;
100119

101120
typedef struct redis_call {

0 commit comments

Comments
 (0)