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.
This commit is contained in:
Sebastian Dröge 2020-01-12 16:18:09 +02:00 committed by GStreamer Merge Bot
parent d66aa872ca
commit 7fcfb6c6c5
6 changed files with 298 additions and 23 deletions

View file

@ -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, &notify_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, &notify_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, &notify_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, &notify_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, &notify_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, &notify_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, &notify_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;
}

View file

@ -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:
*

View file

@ -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);
}
@ -743,6 +757,15 @@ gst_dtls_dec_fetch_connection (gchar * id)
return connection;
}
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)
{
@ -750,6 +773,8 @@ create_connection (GstDtlsDec * self, gchar * id)
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));

View file

@ -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);

View file

@ -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);
@ -146,6 +153,15 @@ gst_dtls_srtp_dec_class_init (GstDtlsSrtpDecClass * klass)
"Patrik Oldsberg patrik.oldsberg@ericsson.com");
}
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)
{
@ -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);
}

View file

@ -28,6 +28,7 @@
#endif
#include "gstdtlssrtpenc.h"
#include "gstdtlsconnection.h"
#include <stdio.h>
@ -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);
@ -152,6 +161,15 @@ gst_dtls_srtp_enc_class_init (GstDtlsSrtpEncClass * klass)
"Patrik Oldsberg patrik.oldsberg@ericsson.com");
}
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)
{
@ -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);
}