Skip to content
This repository has been archived by the owner on Nov 23, 2021. It is now read-only.

srt: add authentication to srtsink and srtsrc elements #6

Open
wants to merge 1 commit into
base: ubuntu/focal
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 84 additions & 3 deletions ext/srt/gstsrtobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ enum
PROP_STATS,
PROP_WAIT_FOR_CONNECTION,
PROP_STREAMID,
PROP_AUTHENTICATION,
PROP_LAST
};

Expand Down Expand Up @@ -352,6 +353,9 @@ gst_srt_object_set_property_helper (GstSRTObject * srtobject,
case PROP_STREAMID:
gst_structure_set_value (srtobject->parameters, "streamid", value);
break;
case PROP_AUTHENTICATION:
srtobject->authentication = g_value_get_boolean (value);
break;
default:
goto err;
}
Expand Down Expand Up @@ -435,7 +439,10 @@ gst_srt_object_get_property_helper (GstSRTObject * srtobject,
g_value_set_string (value,
gst_structure_get_string (srtobject->parameters, "streamid"));
break;
}
}
case PROP_AUTHENTICATION:
g_value_set_boolean (value, srtobject->authentication);
break;
default:
goto err;
}
Expand Down Expand Up @@ -583,6 +590,22 @@ gst_srt_object_install_properties_helper (GObjectClass * gobject_class)
"Stream ID for the SRT access control", "",
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));

/**
* GstSRTSink:authentication:
*
* Boolean to authenticate a connection. If TRUE,
* the incoming connection is authenticated. Else,
* all the connections are accepted.
*
* Since: 1.20
*
*/
g_object_class_install_property (gobject_class, PROP_AUTHENTICATION,
g_param_spec_boolean ("authentication",
"Authentication",
"Authenticate a connection",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}

static void
Expand Down Expand Up @@ -829,6 +852,58 @@ thread_func (gpointer data)
}
}

static GSocketAddress *
peeraddr_to_g_socket_address (const struct sockaddr *peeraddr)
{
gsize peeraddr_len;

switch (peeraddr->sa_family) {
case AF_INET:
peeraddr_len = sizeof (struct sockaddr_in);
break;
case AF_INET6:
peeraddr_len = sizeof (struct sockaddr_in6);
break;
default:
g_warning ("Unsupported address family %d", peeraddr->sa_family);
return NULL;
}
return g_socket_address_new_from_native ((gpointer) peeraddr, peeraddr_len);
}

static gint
srt_listen_callback_func (GstSRTObject * self, SRTSOCKET sock, int hs_version,
const struct sockaddr *peeraddr, const char *stream_id)
{
g_autoptr (GSocketAddress) addr = peeraddr_to_g_socket_address (peeraddr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think at least MSVC doesn't support g_autoptr and the like. We couldn't care less for MSVC in Hwangsaeul, but in upstream GStreamer autocleanup is better avoided.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the Hwangsaeul project supports only the Linux platform and the latest GLib, but GStreamer-wise, we should follow their rules.


if (!addr) {
GST_WARNING_OBJECT (self->element,
"Invalid peer address. Rejecting sink %d streamid: %s", sock,
stream_id);
return -1;
}

if (self->authentication) {
gboolean authenticated = FALSE;

/* notifying caller-connecting */
g_signal_emit_by_name (self->element, "caller-connecting", addr,
raghaven447 marked this conversation as resolved.
Show resolved Hide resolved
stream_id, &authenticated);

if (!authenticated)
goto reject;
}

g_debug ("Accepting sink %d streamid: %s", sock, stream_id);
return 0;
reject:
/* notifying caller-rejected */
g_warning ("Rejecting sink %d streamid: %s", sock, stream_id);
g_signal_emit_by_name (self->element, "caller-rejected");
Copy link
Collaborator

@xhaakon xhaakon Oct 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add some information that identify the rejected caller into the callback. Let's put addr and stream_id as parameters, same as "caller-connecting".

return -1;
}

static gboolean
gst_srt_object_wait_connect (GstSRTObject * srtobject,
GCancellable * cancellable, GSocketFamily sa_family, gpointer sa,
Expand Down Expand Up @@ -910,10 +985,16 @@ gst_srt_object_wait_connect (GstSRTObject * srtobject,

srtobject->listener_sock = sock;

/* Register the SRT listen callback */
if (srt_listen_callback (srtobject->listener_sock,
(srt_listen_callback_fn *) srt_listen_callback_func, srtobject)) {
goto failed;
}

srtobject->thread =
g_thread_try_new ("GstSRTObjectListener", thread_func, srtobject, error);

if (*error != NULL) {
if (srtobject->thread == NULL) {
GST_ERROR_OBJECT (srtobject->element, "Failed to start thread");
goto failed;
}

Expand Down
2 changes: 2 additions & 0 deletions ext/srt/gstsrtobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ struct _GstSRTObject

gboolean wait_for_connection;

gboolean authentication;

guint64 previous_bytes;
};

Expand Down
54 changes: 51 additions & 3 deletions ext/srt/gstsrtsink.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ enum
SIG_CALLER_ADDED,
SIG_CALLER_REMOVED,
SIG_CALLER_REJECTED,

SIG_CALLER_CONNECTING,
LAST_SIGNAL
};

Expand All @@ -69,13 +69,36 @@ static void gst_srt_sink_uri_handler_init (gpointer g_iface,
static gchar *gst_srt_sink_uri_get_uri (GstURIHandler * handler);
static gboolean gst_srt_sink_uri_set_uri (GstURIHandler * handler,
const gchar * uri, GError ** error);
static gboolean default_caller_connecting (GstSRTSink * self,
GSocketAddress * addr, const gchar * username, gpointer data);
static gboolean authentication_accumulator (GSignalInvocationHint * ihint,
GValue * return_accu, const GValue * handler_return, gpointer data);

#define gst_srt_sink_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstSRTSink, gst_srt_sink,
GST_TYPE_BASE_SINK,
G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_srt_sink_uri_handler_init)
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "srtsink", 0, "SRT Sink"));

static gboolean
default_caller_connecting (GstSRTSink * self,
GSocketAddress * addr, const gchar * stream_id, gpointer data)
{
/* Accept all connections. */
return TRUE;
}

static gboolean
authentication_accumulator (GSignalInvocationHint * ihint,
GValue * return_accu, const GValue * handler_return, gpointer data)
{
gboolean ret = g_value_get_boolean (handler_return);
/* Handlers return TRUE on authentication success and we want to stop on
* the first failure. */
g_value_set_boolean (return_accu, ret);
return ret;
}

static void
gst_srt_sink_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
Expand Down Expand Up @@ -274,6 +297,7 @@ gst_srt_sink_class_init (GstSRTSinkClass * klass)
gobject_class->set_property = gst_srt_sink_set_property;
gobject_class->get_property = gst_srt_sink_get_property;
gobject_class->finalize = gst_srt_sink_finalize;
klass->caller_connecting = default_caller_connecting;

/**
* GstSRTSink::caller-added:
Expand Down Expand Up @@ -305,12 +329,37 @@ gst_srt_sink_class_init (GstSRTSinkClass * klass)
/**
* GstSRTSink::caller-rejected:
* @gstsrtsink: the srtsink element that emitted this signal
* @addr: the #GSocketAddress that describes the client socket
* @stream_id: the stream Id to which the caller wants to connect
*
* A caller's connection to srtsink in listener mode has been rejected.
*
* Since: 1.20
*
*/
signals[SIG_CALLER_REJECTED] =
g_signal_new ("caller-rejected", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE,
2, G_TYPE_SOCKET_ADDRESS, G_TYPE_STRING);

/**
* GstSRTSink::caller-connecting:
* @gstsrtsink: the srtsink element that emitted this signal
* @addr: the #GSocketAddress that describes the client socket
* @stream_id: the stream Id to which the caller wants to connect
*
* Whether to accept or reject a caller's connection to srtsink in listener mode.
* The Caller's connection is rejected if the callback returns FALSE, else
* the connection is accepeted.
*
* Since: 1.20
*
*/
signals[SIG_CALLER_CONNECTING] =
g_signal_new ("caller-connecting", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstSRTSinkClass, caller_connecting),
authentication_accumulator, NULL, NULL, G_TYPE_BOOLEAN,
2, G_TYPE_SOCKET_ADDRESS, G_TYPE_STRING);

gst_srt_object_install_properties_helper (gobject_class);

Expand All @@ -326,7 +375,6 @@ gst_srt_sink_class_init (GstSRTSinkClass * klass)
gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_srt_sink_unlock);
gstbasesink_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_srt_sink_unlock_stop);
gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_srt_sink_set_caps);

}

static GstURIType
Expand Down
4 changes: 4 additions & 0 deletions ext/srt/gstsrtsink.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ struct _GstSRTSinkClass {

void (*caller_added) (GstSRTSink *self, int sock, GSocketAddress * addr);
void (*caller_removed) (GstSRTSink *self, int sock, GSocketAddress * addr);
void (*caller_rejected) (GstSRTSink *self, GSocketAddress * peer_address,
const gchar * stream_id, gpointer data);
gboolean (*caller_connecting) (GstSRTSink *self, GSocketAddress * peer_address,
const gchar * stream_id, gpointer data);
};

GType gst_srt_sink_get_type (void);
Expand Down
53 changes: 51 additions & 2 deletions ext/srt/gstsrtsrc.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ enum
SIG_CALLER_ADDED,
SIG_CALLER_REMOVED,
SIG_CALLER_REJECTED,

SIG_CALLER_CONNECTING,
LAST_SIGNAL
};

Expand All @@ -73,13 +73,36 @@ static void gst_srt_src_uri_handler_init (gpointer g_iface,
static gchar *gst_srt_src_uri_get_uri (GstURIHandler * handler);
static gboolean gst_srt_src_uri_set_uri (GstURIHandler * handler,
const gchar * uri, GError ** error);
static gboolean src_default_caller_connecting (GstSRTSrc * self,
GSocketAddress * addr, const gchar * username, gpointer data);
static gboolean src_authentication_accumulator (GSignalInvocationHint * ihint,
GValue * return_accu, const GValue * handler_return, gpointer data);

#define gst_srt_src_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstSRTSrc, gst_srt_src,
GST_TYPE_PUSH_SRC,
G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_srt_src_uri_handler_init)
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "srtsrc", 0, "SRT Source"));

static gboolean
src_default_caller_connecting (GstSRTSrc * self,
GSocketAddress * addr, const gchar * stream_id, gpointer data)
{
/* Accept all connections. */
return TRUE;
}

static gboolean
src_authentication_accumulator (GSignalInvocationHint * ihint,
GValue * return_accu, const GValue * handler_return, gpointer data)
{
gboolean ret = g_value_get_boolean (handler_return);
/* Handlers return TRUE on authentication success and we want to stop on
* the first failure. */
g_value_set_boolean (return_accu, ret);
return ret;
}

static gboolean
gst_srt_src_start (GstBaseSrc * bsrc)
{
Expand Down Expand Up @@ -248,6 +271,7 @@ gst_srt_src_class_init (GstSRTSrcClass * klass)
gobject_class->set_property = gst_srt_src_set_property;
gobject_class->get_property = gst_srt_src_get_property;
gobject_class->finalize = gst_srt_src_finalize;
klass->caller_connecting = src_default_caller_connecting;

/**
* GstSRTSrc::caller-added:
Expand Down Expand Up @@ -279,12 +303,37 @@ gst_srt_src_class_init (GstSRTSrcClass * klass)
/**
* GstSRTSrc::caller-rejected:
* @gstsrtsrc: the srtsrc element that emitted this signal
* @addr: the #GSocketAddress that describes the client socket
* @stream_id: the stream Id to which the caller wants to connect
*
* A caller's connection to srtsrc in listener mode has been rejected.
*
* Since: 1.20
*
*/
signals[SIG_CALLER_REJECTED] =
g_signal_new ("caller-rejected", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstSRTSrcClass, caller_rejected),
NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_SOCKET_ADDRESS, G_TYPE_STRING);

/**
* GstSRTSrc::caller-connecting:
* @gstsrtsrc: the srtsrc element that emitted this signal
* @addr: the #GSocketAddress that describes the client socket
* @stream_id: the stream Id to which the caller wants to connect
*
* Whether to accept or reject a caller's connection to srtsrc in listener mode.
* The Caller's connection is rejected if the callback returns FALSE, else
* the connection is accepeted.
*
* Since: 1.20
*
*/
signals[SIG_CALLER_CONNECTING] =
g_signal_new ("caller-connecting", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstSRTSrcClass, caller_connecting),
src_authentication_accumulator, NULL, NULL, G_TYPE_BOOLEAN,
2, G_TYPE_SOCKET_ADDRESS, G_TYPE_STRING);

gst_srt_object_install_properties_helper (gobject_class);

Expand Down
4 changes: 4 additions & 0 deletions ext/srt/gstsrtsrc.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ struct _GstSRTSrcClass {

void (*caller_added) (GstSRTSrc *self, int sock, GSocketAddress * addr);
void (*caller_removed) (GstSRTSrc *self, int sock, GSocketAddress * addr);
void (*caller_rejected) (GstSRTSrc *self, GSocketAddress * peer_address,
const gchar * stream_id, gpointer data);
gboolean (*caller_connecting) (GstSRTSrc *self, GSocketAddress * peer_address,
const gchar * stream_id, gpointer data);
};

GType gst_srt_src_get_type (void);
Expand Down