[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