[vlc-devel] [patch] Adding AMT module as a network access source. AMT allows IP multicast streams to be tunnelled over a non-multicast enabled networks

Rémi Denis-Courmont remi at remlab.net
Mon Apr 8 21:32:22 CEST 2019


Le torstaina 4. huhtikuuta 2019, 16.35.16 EEST Wayne Brassem a écrit :
> diff --git a/modules/access/amt.c b/modules/access/amt.c
> new file mode 100644
> index 0000000000..5f0e5dcdeb
> --- /dev/null
> +++ b/modules/access/amt.c
> @@ -0,0 +1,1221 @@
> +/**
> + * @file amt.c
> + * @brief Automatic Multicast Tunneling Protocol (AMT) file for VLC media
> player + * Allows multicast streaming when not in a multicast-enabled
> network + * Currently IPv4 is supported, but IPv6 is not yet.
> + *
> + * Copyright (C) 2018 VLC authors and VideoLAN
> + * Copyright (c) Juniper Networks, Inc., 2018. All rights reserved.
> + *
> + * Authors: Christophe Massiot <massiot at via.ecp.fr>           - original
> UDP code + *          Tristan Leteurtre <tooney at via.ecp.fr>             -
> original UDP code + *          Laurent Aimar <fenrir at via.ecp.fr>           
>      - original UDP code + *          Jean-Paul Saman <jpsaman #_at_# m2x
> dot nl>       - original UDP code + *          Remi Denis-Courmont         
>                      - original UDP code + *          Natalie Landsberg
> <natalie.landsberg97 at gmail.com> - AMT support + *          Wayne Brassem
> <wbrassem at rogers.com>               - Added FQDN support + *
> + * This code is licensed to you under the GNU Lesser General Public License
> + * version 2.1 or later. You may not use this code except in compliance
> with + * the GNU Lesser General Public License.
> + * This code is not an official Juniper product.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public License
> + * as published by the Free Software Foundation; either version 2.1
> + * of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 
> USA +
> ***************************************************************************
> */ +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <errno.h>
> +#include <ctype.h>
> +#ifdef HAVE_ARPA_INET_H
> +# include <arpa/inet.h>
> +#endif
> +
> +#ifdef HAVE_SYS_SELECT_H
> +# include <sys/select.h>
> +#endif
> +
> +#ifdef HAVE_SYS_SOCKET_H
> +# include <sys/socket.h>
> +#endif
> +
> +#include <vlc_common.h>
> +#include <vlc_demux.h>
> +#include <vlc_plugin.h>
> +#include <vlc_access.h>
> +#include <vlc_network.h>
> +#include <vlc_block.h>
> +#include <vlc_interrupt.h>
> +#include <vlc_url.h>
> +
> +#include "amt.h"
> +
> +#ifdef HAVE_POLL
> + #include <poll.h>
> +#endif
> +#ifdef HAVE_SYS_UIO_H
> + #include <sys/uio.h>
> +#endif
> +
> +#define BUFFER_TEXT N_("Receive buffer")
> +#define BUFFER_LONGTEXT N_("AMT receive buffer size (bytes)" )
> +#define TIMEOUT_TEXT N_("Native multicast timeout (sec)")
> +#define AMT_TIMEOUT_TEXT N_("AMT timeout (sec)")
> +#define AMT_RELAY_ADDRESS N_("AMT relay (IP address or FQDN)")
> +#define AMT_RELAY_ADDR_LONG N_("AMT relay anycast address, or specify the
> relay you want by address or fully qualified domain name") +#define
> AMT_DEFAULT_RELAY N_("amt-relay.m2icast.net")
> +
> +static int  Open (vlc_object_t *);
> +static void Close (vlc_object_t *);
> +
> +/* Utility functions */
> +static unsigned short get_checksum( unsigned short *buffer, int nLen );
> +static void make_report( amt_igmpv3_membership_report_t *mr );
> +static void make_ip_header( amt_ip_alert_t *p_ipHead );
> +
> +vlc_module_begin ()
> +    set_shortname( N_("AMT" ) )
> +    set_description( N_("AMT input") )
> +    set_category( CAT_INPUT )
> +    set_subcategory( SUBCAT_INPUT_ACCESS )
> +
> +    add_integer( "amt-timeout", 5, AMT_TIMEOUT_TEXT, NULL, true )
> +    add_integer( "amt-native-timeout", 3, TIMEOUT_TEXT, NULL, true )
> +    add_string( "amt-relay", AMT_DEFAULT_RELAY, AMT_RELAY_ADDRESS,
> AMT_RELAY_ADDR_LONG, true ) +
> +    set_capability( "access", 0 )
> +    add_shortcut( "amt" )
> +
> +    set_callbacks( Open, Close )
> +vlc_module_end ()
> +
> +/**************************************************************************
> *** + * Local prototypes
> +
> ***************************************************************************
> **/ +static block_t *BlockUDP( stream_t *, bool * );
> +static int Control( stream_t *, int, va_list );
> +
> +/**************************************************************************
> *** + * Open: Open a connection to the multicast feed
> +
> ***************************************************************************
> **/ +static int Open( vlc_object_t *p_this )
> +{
> +    stream_t            *p_access = (stream_t*) p_this;
> +    access_sys_t        *sys = NULL;
> +    struct addrinfo      hints, *serverinfo = NULL;
> +    struct sockaddr_in  *server_addr;
> +    char                *psz_name = NULL, *saveptr, *psz_strtok_r,
> ip_buffer[INET_ADDRSTRLEN];
> +    int                  i_bind_port = 1234,
> i_server_port = 0, VLC_ret = VLC_SUCCESS, res;
> +    vlc_url_t           
> url;
> +
> +    if( p_access->b_preparsing )
> +        return VLC_EGENERIC;
> +
> +    /* Allocate the structure for holding AMT info and zeroize it */
> +    sys = vlc_obj_calloc( p_this, 1, sizeof( *sys ) );
> +    if( unlikely( sys == NULL ) )
> +        return VLC_ENOMEM;
> +
> +    /* The standard MPEG-2 transport is 188 bytes.  7 packets fit into a
> standard 1500 byte Ethernet frame */
> +    sys->mtu = 7 * 188;
> +
> +    /* Code snippet imported from Open() in udp.c to create packet overflow
> buffer */
> +    sys->overflow_block = block_Alloc(65507 - sys->mtu);
> +    if( unlikely( sys->overflow_block == NULL ) )
> +        return VLC_ENOMEM;

I can't say that I like hacks from udp.c getting copy-pasted here.

This sort of (mal)practice has not gone well in the past (e.g. file->MTP).

> +
> +    p_access->p_sys = sys;
> +
> +    /* Set up p_access */
> +    ACCESS_SET_CALLBACKS( NULL, BlockUDP, Control, NULL );
> +
> +    if( !p_access->psz_location )
> +        return VLC_EGENERIC;
> +
> +    psz_name = strdup( p_access->psz_location );
> +    if ( unlikely( psz_name == NULL ) )
> +        return VLC_ENOMEM;
> +
> +    /* Parse psz_name syntax :
> +     * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
> +    if( vlc_UrlParse( &url, p_access->psz_url ) != 0 )
> +    {
> +        msg_Err( p_access, "Invalid URL: %s", p_access->psz_url );
> +        VLC_ret = VLC_EGENERIC;
> +        goto cleanup;
> +    }
> +
> +    if( url.i_port > 0 )
> +        i_bind_port = url.i_port;
> +
> +    msg_Dbg( p_access, "Opening multicast: %s:%d local=%s:%d",
> +             url.psz_host, i_server_port, url.psz_path, i_bind_port );
> +
> +    if( ( url.psz_host == NULL ) || ( strlen( url.psz_host ) == 0 ) )

Calling strlen() is wasteful here, and the whole stanza is probably useless.

> +    {
> +        msg_Err( p_access, "Please enter a multicast address in the form
> amt://[source_addr@]group_addr using IP address or FQDN" );

Error messages should be errors, not requests.

> +       VLC_ret = VLC_EGENERIC;
> +        goto cleanup;
> +    }
> +
> +    memset( &hints, 0, sizeof( hints ));
> +    hints.ai_family = AF_INET;  /* Setting to AF_UNSPEC accepts both IPv4
> and IPv6 */
> +    hints.ai_socktype = SOCK_DGRAM;
> +
> +    /* Retrieve list of multicast addresses matching the multicast group
> identifier */
> +    res = vlc_getaddrinfo( url.psz_host, AMT_PORT, &hints, &serverinfo );
> +
> +    /* If an error returned print reason and exit */
> +    if( res )
> +    {
> +        msg_Err( p_access, "Could not find multicast group %s, reason: %s",
> url.psz_host, gai_strerror(res) );
> +        VLC_ret = VLC_EGENERIC;
> +        goto cleanup;
> +    }
> +
> +    /* Convert binary socket address to string */
> +    server_addr = (struct sockaddr_in *) serverinfo->ai_addr;
> +    inet_ntop(AF_INET, &(server_addr->sin_addr), ip_buffer,
> INET_ADDRSTRLEN); +
> +    /* Release the allocated memory */
> +    freeaddrinfo( serverinfo );
> +    serverinfo = NULL;
> +
> +    sys->mcastGroup = strdup( ip_buffer );
> +    if( unlikely( sys->mcastGroup == NULL ) )
> +    {
> +        VLC_ret = VLC_ENOMEM;
> +        goto cleanup;
> +    }

No. Compute the value is the most convenient format once and for all. Don't 
convert and convert and convert.

> +
> +    msg_Dbg( p_access, "Setting multicast group address to %s",
> sys->mcastGroup); +
> +    /* Extract the source from the URL, or the multicast group when no
> source is provided */ +    if ( !( psz_strtok_r = strtok_r( psz_name, "@",
> &saveptr ) ) ) +    {
> +        msg_Err( p_access, "Could not parse location %s", psz_name);
> +        VLC_ret = VLC_EGENERIC;
> +        goto cleanup;
> +    }
> +    sys->srcAddr = strdup( psz_strtok_r );

Using strtok(_r) only makes sense within a loop.

> +
> +    if( unlikely( sys->srcAddr == NULL ) )
> +    {
> +        VLC_ret = VLC_ENOMEM;
> +        goto cleanup;
> +    }
> +
> +    /* if strings are equal then no multicast source has been specified */
> +    if( strcmp( url.psz_host, sys->srcAddr ) == 0 )
> +    {
> +        free( sys->srcAddr );
> +        sys->srcAddr = strdup("0.0.0.0");

Come on. That's obviously not how one compares IP addresses.

Also lots of gratuitious casts and similar issues as above

This needs a lot of self review and cleaning up.

-- 
レミ・デニ-クールモン
http://www.remlab.net/





More information about the vlc-devel mailing list