From: Sebastian Dröge Date: Sun, 12 Jan 2020 14:18:09 +0000 (+0200) Subject: dtls: Keep track of the connection state and signal it through all the layers X-Git-Tag: 1.19.3~507^2~2405 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7fcfb6c6c5a58b257d0f6e6d8a843530c42b3fce;p=platform%2Fupstream%2Fgstreamer.git dtls: Keep track of the connection state and signal it through all the layers This allows the application to keep track of the underlying DTLS connection state and act accordingly. --- diff --git a/ext/dtls/gstdtlsconnection.c b/ext/dtls/gstdtlsconnection.c index a3dfeb7..e287030 100644 --- a/ext/dtls/gstdtlsconnection.c +++ b/ext/dtls/gstdtlsconnection.c @@ -69,6 +69,7 @@ enum { PROP_0, PROP_AGENT, + PROP_CONNECTION_STATE, NUM_PROPERTIES }; @@ -87,9 +88,9 @@ struct _GstDtlsConnectionPrivate gboolean is_alive; gboolean keys_exported; + GstDtlsConnectionState connection_state; gboolean sent_close_notify; gboolean received_close_notify; - gboolean fatal_error; GMutex mutex; GCond condition; @@ -113,12 +114,15 @@ G_DEFINE_TYPE_WITH_CODE (GstDtlsConnection, gst_dtls_connection, G_TYPE_OBJECT, static void gst_dtls_connection_finalize (GObject * gobject); static void gst_dtls_connection_set_property (GObject *, guint prop_id, const GValue *, GParamSpec *); +static void gst_dtls_connection_get_property (GObject *, guint prop_id, + GValue *, GParamSpec *); static void log_state (GstDtlsConnection *, const gchar * str); static void export_srtp_keys (GstDtlsConnection *); -static GstFlowReturn openssl_poll (GstDtlsConnection *, GError ** err); +static GstFlowReturn openssl_poll (GstDtlsConnection *, gboolean * notify_state, + GError ** err); static GstFlowReturn handle_error (GstDtlsConnection * self, int ret, - GstResourceError error_type, GError ** err); + GstResourceError error_type, gboolean * notify_state, GError ** err); static int openssl_verify_callback (int preverify_ok, X509_STORE_CTX * x509_ctx); @@ -135,6 +139,7 @@ gst_dtls_connection_class_init (GstDtlsConnectionClass * klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = gst_dtls_connection_set_property; + gobject_class->get_property = gst_dtls_connection_get_property; connection_ex_index = SSL_get_ex_new_index (0, (gpointer) "gstdtlsagent connection index", NULL, @@ -161,6 +166,13 @@ gst_dtls_connection_class_init (GstDtlsConnectionClass * klass) GST_TYPE_DTLS_AGENT, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + properties[PROP_CONNECTION_STATE] = + g_param_spec_enum ("connection-state", + "Connection State", + "Current connection state", + GST_DTLS_TYPE_CONNECTION_STATE, + GST_DTLS_CONNECTION_STATE_NEW, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); _gst_dtls_init_openssl (); @@ -290,12 +302,31 @@ gst_dtls_connection_set_property (GObject * object, guint prop_id, } } +static void +gst_dtls_connection_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstDtlsConnection *self = GST_DTLS_CONNECTION (object); + GstDtlsConnectionPrivate *priv = self->priv; + + switch (prop_id) { + case PROP_CONNECTION_STATE: + g_mutex_lock (&priv->mutex); + g_value_set_enum (value, priv->connection_state); + g_mutex_unlock (&priv->mutex); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); + } +} + gboolean gst_dtls_connection_start (GstDtlsConnection * self, gboolean is_client, GError ** err) { GstDtlsConnectionPrivate *priv; gboolean ret; + gboolean notify_state = FALSE; priv = self->priv; @@ -313,19 +344,26 @@ gst_dtls_connection_start (GstDtlsConnection * self, gboolean is_client, priv->bio_buffer_offset = 0; priv->keys_exported = FALSE; - priv->fatal_error = FALSE; priv->sent_close_notify = FALSE; priv->received_close_notify = FALSE; + /* Client immediately starts connecting, the server waits for a client to + * start the handshake process */ priv->is_client = is_client; if (priv->is_client) { + priv->connection_state = GST_DTLS_CONNECTION_STATE_CONNECTING; + notify_state = TRUE; SSL_set_connect_state (priv->ssl); } else { + if (priv->connection_state != GST_DTLS_CONNECTION_STATE_NEW) { + priv->connection_state = GST_DTLS_CONNECTION_STATE_NEW; + notify_state = TRUE; + } SSL_set_accept_state (priv->ssl); } log_state (self, "initial state set"); - ret = openssl_poll (self, err); + ret = openssl_poll (self, ¬ify_state, err); if (ret == GST_FLOW_EOS && err) { *err = g_error_new_literal (GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_OPEN_WRITE, @@ -337,6 +375,11 @@ gst_dtls_connection_start (GstDtlsConnection * self, gboolean is_client, GST_TRACE_OBJECT (self, "unlocking @ start"); g_mutex_unlock (&priv->mutex); + if (notify_state) { + g_object_notify_by_pspec (G_OBJECT (self), + properties[PROP_CONNECTION_STATE]); + } + return ret == GST_FLOW_OK; } @@ -346,6 +389,7 @@ handle_timeout (gpointer data, gpointer user_data) GstDtlsConnection *self = user_data; GstDtlsConnectionPrivate *priv; gint ret; + gboolean notify_state = FALSE; priv = self->priv; @@ -361,11 +405,16 @@ handle_timeout (gpointer data, gpointer user_data) GST_WARNING_OBJECT (self, "handling timeout failed"); } else if (ret > 0) { log_state (self, "handling timeout before poll"); - openssl_poll (self, NULL); + openssl_poll (self, ¬ify_state, NULL); log_state (self, "handling timeout after poll"); } } g_mutex_unlock (&priv->mutex); + + if (notify_state) { + g_object_notify_by_pspec (G_OBJECT (self), + properties[PROP_CONNECTION_STATE]); + } } static gboolean @@ -456,6 +505,8 @@ gst_dtls_connection_check_timeout (GstDtlsConnection * self) void gst_dtls_connection_stop (GstDtlsConnection * self) { + gboolean notify_state = FALSE; + g_return_if_fail (GST_IS_DTLS_CONNECTION (self)); g_return_if_fail (self->priv->ssl); g_return_if_fail (self->priv->bio); @@ -467,6 +518,11 @@ gst_dtls_connection_stop (GstDtlsConnection * self) GST_TRACE_OBJECT (self, "locked @ stop"); self->priv->is_alive = FALSE; + if (self->priv->connection_state != GST_DTLS_CONNECTION_STATE_FAILED + && self->priv->connection_state != GST_DTLS_CONNECTION_STATE_CLOSED) { + self->priv->connection_state = GST_DTLS_CONNECTION_STATE_CLOSED; + notify_state = TRUE; + } GST_TRACE_OBJECT (self, "signaling @ stop"); g_cond_signal (&self->priv->condition); GST_TRACE_OBJECT (self, "signaled @ stop"); @@ -475,11 +531,18 @@ gst_dtls_connection_stop (GstDtlsConnection * self) g_mutex_unlock (&self->priv->mutex); GST_DEBUG_OBJECT (self, "stopped connection"); + + if (notify_state) { + g_object_notify_by_pspec (G_OBJECT (self), + properties[PROP_CONNECTION_STATE]); + } } void gst_dtls_connection_close (GstDtlsConnection * self) { + gboolean notify_state = FALSE; + g_return_if_fail (GST_IS_DTLS_CONNECTION (self)); g_return_if_fail (self->priv->ssl); g_return_if_fail (self->priv->bio); @@ -495,10 +558,21 @@ gst_dtls_connection_close (GstDtlsConnection * self) g_cond_signal (&self->priv->condition); } + if (self->priv->connection_state != GST_DTLS_CONNECTION_STATE_FAILED + && self->priv->connection_state != GST_DTLS_CONNECTION_STATE_CLOSED) { + self->priv->connection_state = GST_DTLS_CONNECTION_STATE_CLOSED; + notify_state = TRUE; + } + GST_TRACE_OBJECT (self, "unlocking @ close"); g_mutex_unlock (&self->priv->mutex); GST_DEBUG_OBJECT (self, "closed connection"); + + if (notify_state) { + g_object_notify_by_pspec (G_OBJECT (self), + properties[PROP_CONNECTION_STATE]); + } } void @@ -533,6 +607,7 @@ gst_dtls_connection_process (GstDtlsConnection * self, gpointer data, gsize len, GstFlowReturn flow_ret = GST_FLOW_OK; GstDtlsConnectionPrivate *priv; int ret; + gboolean notify_state = FALSE; g_return_val_if_fail (GST_IS_DTLS_CONNECTION (self), 0); g_return_val_if_fail (self->priv->ssl, 0); @@ -552,7 +627,7 @@ gst_dtls_connection_process (GstDtlsConnection * self, gpointer data, gsize len, return GST_FLOW_EOS; } - if (self->priv->fatal_error) { + if (self->priv->connection_state == GST_DTLS_CONNECTION_STATE_FAILED) { GST_ERROR_OBJECT (self, "Had a fatal error before"); g_mutex_unlock (&priv->mutex); if (err) @@ -569,7 +644,7 @@ gst_dtls_connection_process (GstDtlsConnection * self, gpointer data, gsize len, log_state (self, "process start"); if (SSL_want_write (priv->ssl)) { - flow_ret = openssl_poll (self, err); + flow_ret = openssl_poll (self, ¬ify_state, err); log_state (self, "process want write, after poll"); if (flow_ret != GST_FLOW_OK) { g_mutex_unlock (&priv->mutex); @@ -577,34 +652,66 @@ gst_dtls_connection_process (GstDtlsConnection * self, gpointer data, gsize len, } } + /* If we're a server and were in new state then by receiving the first data + * we would start the connection process */ + if (!priv->is_client) { + if (self->priv->connection_state == GST_DTLS_CONNECTION_STATE_NEW) { + priv->connection_state = GST_DTLS_CONNECTION_STATE_CONNECTING; + notify_state = TRUE; + } + } + ret = SSL_read (priv->ssl, data, len); *written = ret >= 0 ? ret : 0; GST_DEBUG_OBJECT (self, "read result: %d", ret); - flow_ret = handle_error (self, ret, GST_RESOURCE_ERROR_READ, err); + flow_ret = + handle_error (self, ret, GST_RESOURCE_ERROR_READ, ¬ify_state, err); if (flow_ret == GST_FLOW_EOS) { self->priv->received_close_notify = TRUE; + if (self->priv->connection_state != GST_DTLS_CONNECTION_STATE_FAILED + && self->priv->connection_state != GST_DTLS_CONNECTION_STATE_CLOSED) { + self->priv->connection_state = GST_DTLS_CONNECTION_STATE_CLOSED; + notify_state = TRUE; + } /* Notify about the connection being properly closed now if both * sides did so */ if (self->priv->sent_close_notify && self->priv->send_callback) self->priv->send_callback (self, NULL, 0, NULL); g_mutex_unlock (&priv->mutex); + + if (notify_state) { + g_object_notify_by_pspec (G_OBJECT (self), + properties[PROP_CONNECTION_STATE]); + } + return flow_ret; } else if (flow_ret != GST_FLOW_OK) { g_mutex_unlock (&priv->mutex); + + if (notify_state) { + g_object_notify_by_pspec (G_OBJECT (self), + properties[PROP_CONNECTION_STATE]); + } + return flow_ret; } log_state (self, "process after read"); - flow_ret = openssl_poll (self, err); + flow_ret = openssl_poll (self, ¬ify_state, err); log_state (self, "process after poll"); GST_TRACE_OBJECT (self, "unlocking @ process"); g_mutex_unlock (&priv->mutex); + if (notify_state) { + g_object_notify_by_pspec (G_OBJECT (self), + properties[PROP_CONNECTION_STATE]); + } + return flow_ret; } @@ -614,6 +721,7 @@ gst_dtls_connection_send (GstDtlsConnection * self, gconstpointer data, { GstFlowReturn flow_ret; int ret = 0; + gboolean notify_state = FALSE; g_return_val_if_fail (GST_IS_DTLS_CONNECTION (self), 0); @@ -624,7 +732,7 @@ gst_dtls_connection_send (GstDtlsConnection * self, gconstpointer data, g_mutex_lock (&self->priv->mutex); GST_TRACE_OBJECT (self, "locked @ send"); - if (self->priv->fatal_error) { + if (self->priv->connection_state == GST_DTLS_CONNECTION_STATE_FAILED) { GST_ERROR_OBJECT (self, "Had a fatal error before"); g_mutex_unlock (&self->priv->mutex); if (err) @@ -644,7 +752,11 @@ gst_dtls_connection_send (GstDtlsConnection * self, gconstpointer data, *written = 0; GST_DEBUG_OBJECT (self, "Sending close_notify"); ret = SSL_shutdown (self->priv->ssl); - self->priv->sent_close_notify = TRUE; + if (self->priv->connection_state != GST_DTLS_CONNECTION_STATE_CLOSED && + self->priv->connection_state != GST_DTLS_CONNECTION_STATE_FAILED) { + self->priv->connection_state = GST_DTLS_CONNECTION_STATE_CLOSED; + notify_state = TRUE; + } if (ret == 1) { GST_LOG_OBJECT (self, "received peer close_notify already"); self->priv->received_close_notify = TRUE; @@ -653,7 +765,9 @@ gst_dtls_connection_send (GstDtlsConnection * self, gconstpointer data, GST_LOG_OBJECT (self, "did not receive peer close_notify yet"); flow_ret = GST_FLOW_OK; } else { - flow_ret = handle_error (self, ret, GST_RESOURCE_ERROR_WRITE, err); + flow_ret = + handle_error (self, ret, GST_RESOURCE_ERROR_WRITE, ¬ify_state, + err); } } else if (SSL_is_init_finished (self->priv->ssl)) { GST_DEBUG_OBJECT (self, "sending data of %" G_GSIZE_FORMAT " B", len); @@ -661,7 +775,9 @@ gst_dtls_connection_send (GstDtlsConnection * self, gconstpointer data, if (ret <= 0) { if (written) *written = 0; - flow_ret = handle_error (self, ret, GST_RESOURCE_ERROR_WRITE, err); + flow_ret = + handle_error (self, ret, GST_RESOURCE_ERROR_WRITE, ¬ify_state, + err); } else { if (written) *written = ret; @@ -682,6 +798,11 @@ gst_dtls_connection_send (GstDtlsConnection * self, gconstpointer data, GST_TRACE_OBJECT (self, "unlocking @ send"); g_mutex_unlock (&self->priv->mutex); + if (notify_state) { + g_object_notify_by_pspec (G_OBJECT (self), + properties[PROP_CONNECTION_STATE]); + } + return flow_ret; } @@ -829,7 +950,7 @@ ssl_err_cb (const char *str, size_t len, void *u) static GstFlowReturn handle_error (GstDtlsConnection * self, int ret, GstResourceError error_type, - GError ** err) + gboolean * notify_state, GError ** err) { int error; @@ -841,7 +962,10 @@ handle_error (GstDtlsConnection * self, int ret, GstResourceError error_type, return GST_FLOW_OK; case SSL_ERROR_SSL: GST_ERROR_OBJECT (self, "Fatal SSL error"); - self->priv->fatal_error = TRUE; + if (self->priv->connection_state != GST_DTLS_CONNECTION_STATE_FAILED) { + self->priv->connection_state = GST_DTLS_CONNECTION_STATE_FAILED; + *notify_state = TRUE; + } ERR_print_errors_cb (ssl_err_cb, self); if (err) *err = @@ -879,12 +1003,18 @@ handle_error (GstDtlsConnection * self, int ret, GstResourceError error_type, *err = g_error_new (GST_RESOURCE_ERROR, error_type, "Fatal SSL syscall error: errno %d: %s", syserror, message); - self->priv->fatal_error = TRUE; + if (self->priv->connection_state != GST_DTLS_CONNECTION_STATE_FAILED) { + self->priv->connection_state = GST_DTLS_CONNECTION_STATE_FAILED; + *notify_state = TRUE; + } return GST_FLOW_ERROR; } } default: - self->priv->fatal_error = TRUE; + if (self->priv->connection_state != GST_DTLS_CONNECTION_STATE_FAILED) { + self->priv->connection_state = GST_DTLS_CONNECTION_STATE_FAILED; + *notify_state = TRUE; + } GST_ERROR_OBJECT (self, "Unknown SSL error: %d, ret: %d", error, ret); if (err) *err = @@ -895,7 +1025,7 @@ handle_error (GstDtlsConnection * self, int ret, GstResourceError error_type, } static GstFlowReturn -openssl_poll (GstDtlsConnection * self, GError ** err) +openssl_poll (GstDtlsConnection * self, gboolean * notify_state, GError ** err) { int ret; GstFlowReturn flow_ret; @@ -913,6 +1043,13 @@ openssl_poll (GstDtlsConnection * self, GError ** err) GST_INFO_OBJECT (self, "handshake just completed successfully, exporting keys"); export_srtp_keys (self); + if (self->priv->connection_state != GST_DTLS_CONNECTION_STATE_FAILED + && self->priv->connection_state != GST_DTLS_CONNECTION_STATE_CLOSED + && self->priv->connection_state != + GST_DTLS_CONNECTION_STATE_CONNECTED) { + self->priv->connection_state = GST_DTLS_CONNECTION_STATE_CONNECTED; + *notify_state = TRUE; + } } else { GST_INFO_OBJECT (self, "handshake is completed"); } @@ -928,7 +1065,9 @@ openssl_poll (GstDtlsConnection * self, GError ** err) break; } - flow_ret = handle_error (self, ret, GST_RESOURCE_ERROR_OPEN_WRITE, err); + flow_ret = + handle_error (self, ret, GST_RESOURCE_ERROR_OPEN_WRITE, notify_state, + err); ERR_print_errors_cb (ssl_warn_cb, self); @@ -1161,3 +1300,24 @@ bio_method_free (BIO * bio) GST_LOG_OBJECT (GST_DTLS_CONNECTION (BIO_get_data (bio)), "BIO free"); return 0; } + +GType +gst_dtls_connection_state_get_type (void) +{ + static GType type = 0; + static const GEnumValue values[] = { + {GST_DTLS_CONNECTION_STATE_NEW, "New connection", "new"}, + {GST_DTLS_CONNECTION_STATE_CLOSED, "Closed connection on either side", + "closed"}, + {GST_DTLS_CONNECTION_STATE_FAILED, "Failed connection", "failed"}, + {GST_DTLS_CONNECTION_STATE_CONNECTING, "Connecting", "connecting"}, + {GST_DTLS_CONNECTION_STATE_CONNECTED, "Successfully connected", + "connected"}, + {0, NULL, NULL}, + }; + + if (!type) { + type = g_enum_register_static ("GstDtlsConnectionState", values); + } + return type; +} diff --git a/ext/dtls/gstdtlsconnection.h b/ext/dtls/gstdtlsconnection.h index 6315ef1..b590486 100644 --- a/ext/dtls/gstdtlsconnection.h +++ b/ext/dtls/gstdtlsconnection.h @@ -65,6 +65,18 @@ typedef enum { #define GST_DTLS_SRTP_MASTER_KEY_LENGTH 30 +typedef enum +{ + GST_DTLS_CONNECTION_STATE_NEW, + GST_DTLS_CONNECTION_STATE_CLOSED, + GST_DTLS_CONNECTION_STATE_FAILED, + GST_DTLS_CONNECTION_STATE_CONNECTING, + GST_DTLS_CONNECTION_STATE_CONNECTED, +} GstDtlsConnectionState; + +GType gst_dtls_connection_state_get_type (void); +#define GST_DTLS_TYPE_CONNECTION_STATE (gst_dtls_connection_state_get_type ()) + /* * GstDtlsConnection: * diff --git a/ext/dtls/gstdtlsdec.c b/ext/dtls/gstdtlsdec.c index bba0035..7b370e2 100644 --- a/ext/dtls/gstdtlsdec.c +++ b/ext/dtls/gstdtlsdec.c @@ -63,10 +63,10 @@ enum PROP_CONNECTION_ID, PROP_PEM, PROP_PEER_PEM, - PROP_DECODER_KEY, PROP_SRTP_CIPHER, PROP_SRTP_AUTH, + PROP_CONNECTION_STATE, NUM_PROPERTIES }; @@ -171,6 +171,13 @@ gst_dtls_dec_class_init (GstDtlsDecClass * klass) 0, GST_DTLS_SRTP_AUTH_HMAC_SHA1_80, DEFAULT_SRTP_AUTH, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + properties[PROP_CONNECTION_STATE] = + g_param_spec_enum ("connection-state", + "Connection State", + "Current connection state", + GST_DTLS_TYPE_CONNECTION_STATE, + GST_DTLS_CONNECTION_STATE_NEW, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); gst_element_class_add_static_pad_template (element_class, &src_template); @@ -301,6 +308,13 @@ gst_dtls_dec_get_property (GObject * object, guint prop_id, GValue * value, case PROP_SRTP_AUTH: g_value_set_uint (value, self->srtp_auth); break; + case PROP_CONNECTION_STATE: + if (self->connection) + g_object_get_property (G_OBJECT (self->connection), "connection-state", + value); + else + g_value_set_enum (value, GST_DTLS_CONNECTION_STATE_CLOSED); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); } @@ -744,12 +758,23 @@ gst_dtls_dec_fetch_connection (gchar * id) } static void +on_connection_state_changed (GObject * object, GParamSpec * pspec, + gpointer user_data) +{ + GstDtlsDec *self = GST_DTLS_DEC (user_data); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CONNECTION_STATE]); +} + +static void create_connection (GstDtlsDec * self, gchar * id) { g_return_if_fail (GST_IS_DTLS_DEC (self)); g_return_if_fail (GST_IS_DTLS_AGENT (self->agent)); if (self->connection) { + g_signal_handlers_disconnect_by_func (self->connection, + on_connection_state_changed, self); g_object_unref (self->connection); self->connection = NULL; } @@ -769,6 +794,10 @@ create_connection (GstDtlsDec * self, gchar * id) self->connection = g_object_new (GST_TYPE_DTLS_CONNECTION, "agent", self->agent, NULL); + g_signal_connect_object (self->connection, + "notify::connection-state", G_CALLBACK (on_connection_state_changed), + self, 0); + on_connection_state_changed (NULL, NULL, self); g_object_weak_ref (G_OBJECT (self->connection), (GWeakNotify) connection_weak_ref_notify, g_strdup (id)); diff --git a/ext/dtls/gstdtlsenc.c b/ext/dtls/gstdtlsenc.c index fd59722..e64ee4d 100644 --- a/ext/dtls/gstdtlsenc.c +++ b/ext/dtls/gstdtlsenc.c @@ -62,10 +62,10 @@ enum PROP_0, PROP_CONNECTION_ID, PROP_IS_CLIENT, - PROP_ENCODER_KEY, PROP_SRTP_CIPHER, PROP_SRTP_AUTH, + PROP_CONNECTION_STATE, NUM_PROPERTIES }; @@ -160,6 +160,13 @@ gst_dtls_enc_class_init (GstDtlsEncClass * klass) 0, GST_DTLS_SRTP_AUTH_HMAC_SHA1_80, DEFAULT_SRTP_AUTH, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + properties[PROP_CONNECTION_STATE] = + g_param_spec_enum ("connection-state", + "Connection State", + "Current connection state", + GST_DTLS_TYPE_CONNECTION_STATE, + GST_DTLS_CONNECTION_STATE_NEW, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); gst_element_class_add_static_pad_template (element_class, &src_template); @@ -269,11 +276,27 @@ gst_dtls_enc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_SRTP_AUTH: g_value_set_uint (value, self->srtp_auth); break; + case PROP_CONNECTION_STATE: + if (self->connection) + g_object_get_property (G_OBJECT (self->connection), "connection-state", + value); + else + g_value_set_enum (value, GST_DTLS_CONNECTION_STATE_CLOSED); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); } } +static void +on_connection_state_changed (GObject * object, GParamSpec * pspec, + gpointer user_data) +{ + GstDtlsEnc *self = GST_DTLS_ENC (user_data); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CONNECTION_STATE]); +} + static GstStateChangeReturn gst_dtls_enc_change_state (GstElement * element, GstStateChange transition) { @@ -294,6 +317,10 @@ gst_dtls_enc_change_state (GstElement * element, GstStateChange transition) g_signal_connect_object (self->connection, "on-encoder-key", G_CALLBACK (on_key_received), self, 0); + g_signal_connect_object (self->connection, + "notify::connection-state", + G_CALLBACK (on_connection_state_changed), self, 0); + on_connection_state_changed (NULL, NULL, self); gst_dtls_connection_set_send_callback (self->connection, (GstDtlsConnectionSendCallback) on_send_data, self, NULL); diff --git a/ext/dtls/gstdtlssrtpdec.c b/ext/dtls/gstdtlssrtpdec.c index 06e6ddd..72abfda 100644 --- a/ext/dtls/gstdtlssrtpdec.c +++ b/ext/dtls/gstdtlssrtpdec.c @@ -28,7 +28,6 @@ #endif #include "gstdtlssrtpdec.h" - #include "gstdtlsconnection.h" static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", @@ -69,6 +68,7 @@ enum PROP_0, PROP_PEM, PROP_PEER_PEM, + PROP_CONNECTION_STATE, NUM_PROPERTIES }; @@ -132,6 +132,13 @@ gst_dtls_srtp_dec_class_init (GstDtlsSrtpDecClass * klass) "The X509 certificate received in the DTLS handshake, in PEM format", DEFAULT_PEER_PEM, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + properties[PROP_CONNECTION_STATE] = + g_param_spec_enum ("connection-state", + "Connection State", + "Current connection state", + GST_DTLS_TYPE_CONNECTION_STATE, + GST_DTLS_CONNECTION_STATE_NEW, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); gst_element_class_add_static_pad_template (element_class, &sink_template); @@ -147,6 +154,15 @@ gst_dtls_srtp_dec_class_init (GstDtlsSrtpDecClass * klass) } static void +on_connection_state_changed (GObject * object, GParamSpec * pspec, + gpointer user_data) +{ + GstDtlsSrtpDec *self = GST_DTLS_SRTP_DEC (user_data); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CONNECTION_STATE]); +} + +static void gst_dtls_srtp_dec_init (GstDtlsSrtpDec * self) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (self)); @@ -226,6 +242,8 @@ gst_dtls_srtp_dec_init (GstDtlsSrtpDec * self) G_CALLBACK (on_decoder_request_key), self); g_signal_connect (self->bin.dtls_element, "notify::peer-pem", G_CALLBACK (on_peer_pem), self); + g_signal_connect (self->bin.dtls_element, "notify::connection-state", + G_CALLBACK (on_connection_state_changed), self); } static void @@ -269,6 +287,10 @@ gst_dtls_srtp_dec_get_property (GObject * object, GST_WARNING_OBJECT (self, "tried to get peer-pem after disabling DTLS"); } break; + case PROP_CONNECTION_STATE: + g_object_get_property (G_OBJECT (self->bin.dtls_element), + "connection-state", value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); } diff --git a/ext/dtls/gstdtlssrtpenc.c b/ext/dtls/gstdtlssrtpenc.c index 5a2db43..d993549 100644 --- a/ext/dtls/gstdtlssrtpenc.c +++ b/ext/dtls/gstdtlssrtpenc.c @@ -28,6 +28,7 @@ #endif #include "gstdtlssrtpenc.h" +#include "gstdtlsconnection.h" #include @@ -76,6 +77,7 @@ enum { PROP_0, PROP_IS_CLIENT, + PROP_CONNECTION_STATE, NUM_PROPERTIES }; @@ -136,6 +138,13 @@ gst_dtls_srtp_enc_class_init (GstDtlsSrtpEncClass * klass) DEFAULT_IS_CLIENT, GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + properties[PROP_CONNECTION_STATE] = + g_param_spec_enum ("connection-state", + "Connection State", + "Current connection state", + GST_DTLS_TYPE_CONNECTION_STATE, + GST_DTLS_CONNECTION_STATE_NEW, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties); gst_element_class_add_static_pad_template (element_class, &rtp_sink_template); @@ -153,6 +162,15 @@ gst_dtls_srtp_enc_class_init (GstDtlsSrtpEncClass * klass) } static void +on_connection_state_changed (GObject * object, GParamSpec * pspec, + gpointer user_data) +{ + GstDtlsSrtpEnc *self = GST_DTLS_SRTP_ENC (user_data); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CONNECTION_STATE]); +} + +static void gst_dtls_srtp_enc_init (GstDtlsSrtpEnc * self) { GstElementClass *klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (self)); @@ -215,6 +233,9 @@ gst_dtls_srtp_enc_init (GstDtlsSrtpEnc * self) g_object_set (self->srtp_enc, "random-key", TRUE, NULL); + g_signal_connect (self->bin.dtls_element, "notify::connection-state", + G_CALLBACK (on_connection_state_changed), self); + g_object_bind_property (G_OBJECT (self), "key", self->srtp_enc, "key", G_BINDING_DEFAULT); g_object_bind_property_full (G_OBJECT (self), "srtp-cipher", self->srtp_enc, @@ -289,6 +310,10 @@ gst_dtls_srtp_enc_get_property (GObject * object, "tried to get is-client after disabling DTLS"); } break; + case PROP_CONNECTION_STATE: + g_object_get_property (G_OBJECT (self->bin.dtls_element), + "connection-state", value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); }