[vlc-devel] [PATCH 3/3] access: srt: add listener mode
Justin Kim
justin.kim at collabora.com
Mon Apr 9 03:05:09 CEST 2018
SRT provides a listener mode to wait for being
contacted by any peer which runs in a caller mode.
Signed-off-by: Justin Kim <justin.kim at collabora.com>
---
modules/access/srt.c | 221 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 188 insertions(+), 33 deletions(-)
diff --git a/modules/access/srt.c b/modules/access/srt.c
index 7523ea4527..7b89a85d5a 100644
--- a/modules/access/srt.c
+++ b/modules/access/srt.c
@@ -60,21 +60,27 @@ enum {
SRT_MODE_CALLER,
SRT_MODE_CLIENT = SRT_MODE_CALLER,
SRT_MODE_RENDEZVOUS,
+ SRT_MODE_LISTENER,
+ SRT_MODE_SERVER = SRT_MODE_LISTENER,
SRT_MODE_UNKNOWN,
};
static const int srt_modes[] = {
SRT_MODE_CALLER,
SRT_MODE_RENDEZVOUS,
+ SRT_MODE_LISTENER,
};
#define SRT_MODE_CALLER_STR "caller"
#define SRT_MODE_CLIENT_STR "client"
#define SRT_MODE_RENDEZVOUS_STR "rendezvous"
+#define SRT_MODE_LISTENER_STR "listener"
+#define SRT_MODE_SERVER_STR "server"
static const char *const srt_mode_names[] = {
N_(SRT_MODE_CALLER_STR),
N_(SRT_MODE_RENDEZVOUS_STR),
+ N_(SRT_MODE_LISTENER_STR),
};
struct stream_sys_t
@@ -86,8 +92,38 @@ struct stream_sys_t
char *psz_host;
int i_port;
int i_mode;
+ SRTSOCKET bind_sock;
+ int i_bind_poll_id;
};
+static void srt_socket_configure (SRTSOCKET sock, int i_latency, const char *psz_passphrase, int i_key_length)
+{
+ /* Make SRT non-blocking */
+ srt_setsockopt( sock, 0, SRTO_SNDSYN,
+ &(bool) { false }, sizeof( bool ) );
+ srt_setsockopt( sock, 0, SRTO_RCVSYN,
+ &(bool) { false }, sizeof( bool ) );
+
+ /* Make sure TSBPD mode is enable (SRT mode) */
+ srt_setsockopt( sock, 0, SRTO_TSBPDMODE,
+ &(int) { 1 }, sizeof( int ) );
+
+ /* This is an access module so it is always a receiver */
+ srt_setsockopt( sock, 0, SRTO_SENDER,
+ &(int) { 0 }, sizeof( int ) );
+
+ srt_setsockopt( sock, 0, SRTO_TSBPDDELAY,
+ &i_latency, sizeof( int ) );
+
+ if ( psz_passphrase != NULL && psz_passphrase[0] != '\0')
+ {
+ srt_setsockopt( sock, 0, SRTO_PASSPHRASE,
+ psz_passphrase, strlen( psz_passphrase ) );
+ srt_setsockopt( sock, 0, SRTO_PBKEYLEN,
+ &i_key_length, sizeof( int ) );
+ }
+}
+
static int srt_get_mode_from_name(const char *psz_mode)
{
int i_mode = SRT_MODE_UNKNOWN;
@@ -101,6 +137,11 @@ static int srt_get_mode_from_name(const char *psz_mode)
{
i_mode = SRT_MODE_RENDEZVOUS;
}
+ else if ( !strncmp( psz_mode, SRT_MODE_LISTENER_STR, strlen( SRT_MODE_LISTENER_STR ) )
+ || !strncmp( psz_mode, SRT_MODE_SERVER_STR, strlen( SRT_MODE_SERVER_STR ) ) )
+ {
+ i_mode = SRT_MODE_LISTENER;
+ }
return i_mode;
}
@@ -121,6 +162,12 @@ static void srt_wait_interrupted(void *p_data)
* wakes up SRT's threads. We only have one to remove. */
srt_epoll_remove_usock( p_sys->i_poll_id, p_sys->sock );
}
+
+ if ( p_sys->i_bind_poll_id >= 0 && p_sys->bind_sock != SRT_INVALID_SOCK )
+ {
+ srt_epoll_remove_usock( p_sys->i_bind_poll_id, p_sys->bind_sock );
+ }
+
vlc_mutex_unlock( &p_sys->lock );
}
@@ -148,11 +195,120 @@ static int Control(stream_t *p_stream, int i_query, va_list args)
return i_ret;
}
+static bool srt_schedule_listen(stream_t *p_stream)
+{
+ int i_latency;
+ int i_stat;
+ char *psz_passphrase = NULL;
+ int i_key_length;
+ int i_poll_timeout;
+
+ struct addrinfo hints = {
+ .ai_socktype = SOCK_DGRAM,
+ }, *res = NULL;
+
+ struct sockaddr client_sa;
+ int client_sa_len;
+
+ stream_sys_t *p_sys = p_stream->p_sys;
+
+ /* Bind server only if bind socket is invalid */
+ if ( p_sys->bind_sock == SRT_INVALID_SOCK )
+ {
+ if ( ( i_stat = vlc_getaddrinfo( p_sys->psz_host, p_sys->i_port, &hints, &res ) ) )
+ {
+ msg_Err( p_stream, "Cannot resolve [%s]:%d (reason: %s)",
+ p_sys->psz_host,
+ p_sys->i_port,
+ gai_strerror( i_stat ) );
+ goto failed;
+ }
+
+ p_sys->bind_sock = srt_socket( res->ai_family, SOCK_DGRAM, 0 );
+ if ( p_sys->bind_sock == SRT_INVALID_SOCK )
+ {
+ msg_Err( p_stream, "Failed to open server(listener) socket." );
+ goto failed;
+ }
+
+ i_latency = var_InheritInteger( p_stream, "latency" );
+ psz_passphrase = var_InheritString( p_stream, "passphrase" );
+ i_key_length = var_InheritInteger( p_stream, "key-length" );
+
+ srt_socket_configure( p_sys->bind_sock, i_latency, psz_passphrase, i_key_length );
+ free( psz_passphrase );
+
+ srt_epoll_add_usock( p_sys->i_bind_poll_id, p_sys->bind_sock,
+ &(int) { SRT_EPOLL_ERR | SRT_EPOLL_IN });
+
+ if ( srt_bind( p_sys->bind_sock, res->ai_addr, res->ai_addrlen) == SRT_ERROR )
+ {
+ msg_Err( p_stream, "Failed to bind to [%s]:%d (reason: %s)",
+ p_sys->psz_host,
+ p_sys->i_port,
+ srt_getlasterror_str() );
+
+ goto failed;
+ }
+
+ if ( srt_listen( p_sys->bind_sock, 1 ) == SRT_ERROR )
+ {
+ msg_Err( p_stream, "Failed to listen to binding socket (reason: %s)",
+ srt_getlasterror_str() );
+ goto failed;
+ }
+ }
+
+ /* Only one client connection is allowed */
+ if (p_sys->sock != SRT_INVALID_SOCK)
+ {
+ srt_epoll_remove_usock( p_sys->i_poll_id, p_sys->sock );
+ srt_close( p_sys->sock );
+ }
+
+ SRTSOCKET ready[1];
+ int readycnt = 1;
+
+ i_poll_timeout = var_InheritInteger( p_stream, "poll-timeout" );
+
+ if ( srt_epoll_wait( p_sys->i_bind_poll_id,
+ ready, &readycnt, 0, 0,
+ i_poll_timeout, NULL, 0, NULL, 0 ) >= 0)
+ {
+ if ( readycnt < 0 || ready[0] != p_sys->bind_sock )
+ {
+ goto failed;
+ }
+ }
+
+ p_sys->sock = srt_accept( p_sys->bind_sock, &client_sa, &client_sa_len );
+ if ( p_sys->sock == SRT_INVALID_SOCK )
+ {
+ goto failed;
+ }
+
+ srt_epoll_add_usock( p_sys->i_poll_id, p_sys->sock,
+ &(int) { SRT_EPOLL_ERR | SRT_EPOLL_IN } );
+
+ freeaddrinfo( res );
+
+ return true;
+
+failed:
+ freeaddrinfo( res );
+
+ srt_close( p_sys->bind_sock );
+ p_sys->bind_sock = SRT_INVALID_SOCK;
+
+ return false;
+}
+
static bool srt_schedule_reconnect(stream_t *p_stream)
{
int i_latency;
int stat;
char *psz_passphrase = NULL;
+ int i_key_length;
struct addrinfo hints = {
.ai_socktype = SOCK_DGRAM,
@@ -188,24 +344,11 @@ static bool srt_schedule_reconnect(stream_t *p_stream)
goto out;
}
- /* Make SRT non-blocking */
- srt_setsockopt( p_sys->sock, 0, SRTO_SNDSYN,
- &(bool) { false }, sizeof( bool ) );
- srt_setsockopt( p_sys->sock, 0, SRTO_RCVSYN,
- &(bool) { false }, sizeof( bool ) );
-
- /* Make sure TSBPD mode is enable (SRT mode) */
- srt_setsockopt( p_sys->sock, 0, SRTO_TSBPDMODE,
- &(int) { 1 }, sizeof( int ) );
-
- /* This is an access module so it is always a receiver */
- srt_setsockopt( p_sys->sock, 0, SRTO_SENDER,
- &(int) { 0 }, sizeof( int ) );
-
- /* Set latency */
i_latency = var_InheritInteger( p_stream, "latency" );
- srt_setsockopt( p_sys->sock, 0, SRTO_TSBPDDELAY,
- &i_latency, sizeof( int ) );
+ psz_passphrase = var_InheritString( p_stream, "passphrase" );
+ i_key_length = var_InheritInteger( p_stream, "key-length" );
+
+ srt_socket_configure( p_sys->sock, i_latency, psz_passphrase, i_key_length );
if ( p_sys->i_mode == SRT_MODE_RENDEZVOUS )
{
@@ -239,16 +382,6 @@ static bool srt_schedule_reconnect(stream_t *p_stream)
freeaddrinfo( loc );
}
- psz_passphrase = var_InheritString( p_stream, "passphrase" );
- if ( psz_passphrase != NULL && psz_passphrase[0] != '\0')
- {
- int i_key_length = var_InheritInteger( p_stream, "key-length" );
- srt_setsockopt( p_sys->sock, 0, SRTO_PASSPHRASE,
- psz_passphrase, strlen( psz_passphrase ) );
- srt_setsockopt( p_sys->sock, 0, SRTO_PBKEYLEN,
- &i_key_length, sizeof( int ) );
- }
-
srt_epoll_add_usock( p_sys->i_poll_id, p_sys->sock,
&(int) { SRT_EPOLL_ERR | SRT_EPOLL_IN });
@@ -319,9 +452,17 @@ static block_t *BlockSRT(stream_t *p_stream, bool *restrict eof)
case SRTS_BROKEN:
case SRTS_NONEXIST:
case SRTS_CLOSED:
- /* Failed. Schedule recovery. */
- if ( !srt_schedule_reconnect( p_stream ) )
- msg_Err( p_stream, "Failed to schedule connect" );
+ if ( p_sys->i_mode == SRT_MODE_LISTENER )
+ {
+ if ( !srt_schedule_listen( p_stream ) )
+ msg_Err( p_stream, "Failed to schedule listen" );
+ }
+ else
+ {
+ /* Failed. Schedule recovery. */
+ if ( !srt_schedule_reconnect( p_stream ) )
+ msg_Err( p_stream, "Failed to schedule connect" );
+ }
/* Fall-through */
default:
/* Not ready */
@@ -432,11 +573,25 @@ static int Open(vlc_object_t *p_this)
goto failed;
}
- if ( !srt_schedule_reconnect( p_stream ) )
+ if ( p_sys->i_mode == SRT_MODE_CALLER || p_sys->i_mode == SRT_MODE_RENDEZVOUS )
{
- msg_Err( p_stream, "Failed to schedule connect");
+ if ( !srt_schedule_reconnect( p_stream ) )
+ {
+ msg_Err( p_stream, "Failed to schedule connect");
- goto failed;
+ goto failed;
+ }
+ }
+ else if ( p_sys->i_mode == SRT_MODE_LISTENER )
+ {
+ p_sys->i_bind_poll_id = srt_epoll_create();
+ /* Invalidate bind socket to make sure creating one */
+ p_sys->bind_sock = SRT_INVALID_SOCK;
+ if ( !srt_schedule_listen( p_stream ) )
+ {
+ msg_Err( p_stream, "Failed to listen to client request");
+ goto failed;
+ }
}
p_stream->pf_block = BlockSRT;
--
2.17.0
More information about the vlc-devel
mailing list