diff --git a/daemon/call.c b/daemon/call.c index f1a79a4fe..03a084c41 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -930,9 +930,9 @@ enum call_stream_state call_stream_state_machine(struct packet_stream *ps) { if (MEDIA_ISSET(media, DTLS)) { mutex_lock(&ps->in_lock); - struct stream_fd *sfd = dtls_sfd(ps); - if (sfd && sfd->dtls.init && !sfd->dtls.connected) { - dtls(sfd, NULL, NULL); + struct dtls_connection *d = dtls_ptr(ps->selected_sfd); + if (d && d->init && !d->connected) { + dtls(ps->selected_sfd, NULL, NULL); mutex_unlock(&ps->in_lock); return CSS_DTLS; } @@ -963,16 +963,20 @@ static int __init_stream(struct packet_stream *ps) { } if (MEDIA_ISSET(media, DTLS) && !PS_ISSET(ps, FALLBACK_RTCP)) { - struct stream_fd *sfd = dtls_sfd(ps); - if (sfd) - active = dtls_is_active(&sfd->dtls); + struct dtls_connection *d = dtls_ptr(ps->selected_sfd); + if (d) + active = dtls_is_active(d); // we try to retain our role if possible, but must handle a role switch if ((active && !MEDIA_ISSET(media, SETUP_ACTIVE)) || (!active && !MEDIA_ISSET(media, SETUP_PASSIVE))) active = -1; if (active == -1) active = (PS_ISSET(ps, FILLED) && MEDIA_ISSET(media, SETUP_ACTIVE)); - dtls_connection_init(ps, active, call->dtls_cert); + dtls_connection_init(&ps->ice_dtls, ps, active, call->dtls_cert); + for (GList *l = ps->sfds.head; l; l = l->next) { + struct stream_fd *sfd = l->data; + dtls_connection_init(&sfd->dtls, ps, active, call->dtls_cert); + } if (!PS_ISSET(ps, FINGERPRINT_VERIFIED) && media->fingerprint.hash_func && ps->dtls_cert) diff --git a/daemon/call.h b/daemon/call.h index 8147dc93b..778928a0a 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -275,6 +275,7 @@ struct packet_stream { GQueue sfds; /* LOCK: call->master_lock */ struct stream_fd * volatile selected_sfd; + struct dtls_connection ice_dtls; /* LOCK: in_lock */ struct packet_stream *rtp_sink; /* LOCK: call->master_lock */ struct packet_stream *rtcp_sink; /* LOCK: call->master_lock */ struct packet_stream *rtcp_sibling; /* LOCK: call->master_lock */ diff --git a/daemon/dtls.c b/daemon/dtls.c index 63d8dd412..793f4abc2 100644 --- a/daemon/dtls.c +++ b/daemon/dtls.c @@ -35,29 +35,12 @@ #define CERT_EXPIRY_TIME (60*60*24*30) /* 30 days */ -INLINE struct stream_fd *dtls_primary(struct packet_stream *ps) { - if (!ps->sfds.length) - return NULL; - return ps->sfds.head->data; -} -// determine the sfd to hold our DTLS context if we don't know the sfd. -// it's either the "selected_sfd" for regular multi-homed streams, or -// the first sfd in the list in case ICE is in use -struct stream_fd *dtls_sfd(struct packet_stream *ps) { - if (!ps) - return NULL; - if (PS_ISSET(ps, ICE)) - return dtls_primary(ps); - return ps->selected_sfd; -} -// determine the DTLS context if we do have an sfd. can be sfd->dtls, -// or in case ICE is in use, the first sfd's context. struct dtls_connection *dtls_ptr(struct stream_fd *sfd) { if (!sfd) return NULL; struct packet_stream *ps = sfd->stream; if (PS_ISSET(ps, ICE)) // ignore which sfd we were given - sfd = dtls_primary(ps); + return &ps->ice_dtls; return &sfd->dtls; } @@ -403,15 +386,15 @@ struct dtls_cert *dtls_cert() { static int verify_callback(int ok, X509_STORE_CTX *store) { SSL *ssl; - struct stream_fd *sfd; + struct dtls_connection *d; struct packet_stream *ps; struct call_media *media; ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()); - sfd = SSL_get_app_data(ssl); - if (sfd->dtls.ssl != ssl) + d = SSL_get_app_data(ssl); + if (d->ssl != ssl) return 0; - ps = sfd->stream; + ps = d->ptr; if (!ps) return 0; if (PS_ISSET(ps, FINGERPRINT_VERIFIED)) @@ -499,15 +482,11 @@ static int try_connect(struct dtls_connection *d) { return ret; } -int dtls_connection_init(struct packet_stream *ps, int active, struct dtls_cert *cert) { - struct dtls_connection *d; +int dtls_connection_init(struct dtls_connection *d, struct packet_stream *ps, int active, + struct dtls_cert *cert) +{ unsigned long err; - struct stream_fd *sfd = dtls_sfd(ps); - if (!sfd) - return 0; - d = &sfd->dtls; - __DBG("dtls_connection_init(%i)", active); if (d->init) { @@ -516,6 +495,8 @@ int dtls_connection_init(struct packet_stream *ps, int active, struct dtls_cert dtls_connection_cleanup(d); } + d->ptr = ps; + #if OPENSSL_VERSION_NUMBER >= 0x10002000L d->ssl_ctx = SSL_CTX_new(active ? DTLS_client_method() : DTLS_server_method()); #else @@ -548,7 +529,7 @@ int dtls_connection_init(struct packet_stream *ps, int active, struct dtls_cert if (!d->r_bio || !d->w_bio) goto error; - SSL_set_app_data(d->ssl, sfd); /* XXX obj reference here? */ + SSL_set_app_data(d->ssl, d); SSL_set_bio(d->ssl, d->r_bio, d->w_bio); d->init = 1; SSL_set_mode(d->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); diff --git a/daemon/dtls.h b/daemon/dtls.h index 68b662826..efba1eb2c 100644 --- a/daemon/dtls.h +++ b/daemon/dtls.h @@ -50,6 +50,7 @@ struct dtls_connection { SSL_CTX *ssl_ctx; SSL *ssl; BIO *r_bio, *w_bio; + void *ptr; int init:1, active:1, connected:1; @@ -65,7 +66,7 @@ int dtls_verify_cert(struct packet_stream *ps); const struct dtls_hash_func *dtls_find_hash_func(const str *); struct dtls_cert *dtls_cert(void); -int dtls_connection_init(struct packet_stream *, int active, struct dtls_cert *cert); +int dtls_connection_init(struct dtls_connection *, struct packet_stream *, int active, struct dtls_cert *cert); int dtls(struct stream_fd *, const str *s, const endpoint_t *sin); void dtls_connection_cleanup(struct dtls_connection *); void dtls_shutdown(struct packet_stream *ps); @@ -109,7 +110,6 @@ INLINE int dtls_is_active(const struct dtls_connection *d) { } -struct stream_fd *dtls_sfd(struct packet_stream *ps); struct dtls_connection *dtls_ptr(struct stream_fd *sfd); diff --git a/daemon/ssrc.c b/daemon/ssrc.c index c5e21aa7f..28310bce2 100644 --- a/daemon/ssrc.c +++ b/daemon/ssrc.c @@ -45,7 +45,6 @@ static void free_stats_block(struct ssrc_stats_block *ssb) { } static void __free_ssrc_entry_call(void *ep) { struct ssrc_entry_call *e = ep; - ilog(LOG_DEBUG, "__free_ssrc_entry_call"); g_queue_clear_full(&e->sender_reports, (GDestroyNotify) free_sender_report); g_queue_clear_full(&e->rr_time_reports, (GDestroyNotify) free_rr_time); g_queue_clear_full(&e->stats_blocks, (GDestroyNotify) free_stats_block);