[vlc-devel] [PATCH] [RESEND] Add support for AMT multicast tunneling over non-multicast enabled networks

Rémi Denis-Courmont remi at remlab.net
Wed May 15 19:17:41 CEST 2019


Le maanantaina 13. toukokuuta 2019, 17.51.21 EEST Wayne Brassem a écrit :
> Resend of submission sent on May 6th.
> 
> ----------------------------------------------
> 
> Updated submission.  The last one was on April 29.
> 
> Changes in this version based on the two previous code reviews:
> 1. Eliminated a redundant malloc() and strcpy() operation per call to
> BlockUDP(). 2. Upon inspection it was indeed obvious that there was
> considerable and inefficient usage of ntop and pton for IP address format
> conversion throughout.  This issue has been addressed and kept to a
> minimum, however because both the string and binary IP address formats are
> used regularly both are retained in the data structures. 3. All IP address
> comparisons are done using numeric form except for a single strcmp()
> occurrence where it is necessary. 4. The protective buffer approach was
> imported from upd.c to address the potential to receive maximal IPv4 UDP
> frames.  The alternative of allocating a pathologically large buffer for
> each packet received when not required is inefficient. 5. The usage of
> strtok_r() was added based on the code review comments on an much earlier
> version of this module which used strtok() because it was not thread safe. 
> It’s probably safer this way, but if strtok is preferred that’s easy to
> change.
> 
> As always, additional comments and suggestions are welcome.
> Wayne.
> 
> ---
>  modules/access/Makefile.am |    4 +
>  modules/access/amt.c       | 1226 ++++++++++++++++++++++++++++++++++++
>  modules/access/amt.h       |  220 +++++++
>  3 files changed, 1450 insertions(+)
>  create mode 100644 modules/access/amt.c
>  create mode 100644 modules/access/amt.h
> 
> diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
> index 9cdf98e0a1..fec9c32005 100644
> --- a/modules/access/Makefile.am
> +++ b/modules/access/Makefile.am
> @@ -373,6 +373,10 @@ libudp_plugin_la_SOURCES = access/udp.c
>  libudp_plugin_la_LIBADD = $(SOCKET_LIBS)
>  access_LTLIBRARIES += libudp_plugin.la <http://libudp_plugin.la/>
> 
> +libamt_plugin_la_SOURCES = access/amt.c access/amt.h
> +libamt_plugin_la_LIBADD = $(SOCKET_LIBS)
> +access_LTLIBRARIES += libamt_plugin.la <http://libamt_plugin.la/>
> +
>  libunc_plugin_la_SOURCES = access/unc.c access/smb_common.h
>  libunc_plugin_la_LIBADD = -lmpr -lnetapi32
>  if HAVE_WIN32
> diff --git a/modules/access/amt.c b/modules/access/amt.c
> new file mode 100644
> index 0000000000..e1e5e61158
> --- /dev/null
> +++ b/modules/access/amt.c
> @@ -0,0 +1,1226 @@
> +/**
> + * @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
> <mailto:massiot at via.ecp.fr>>           - original UDP code + *         
> Tristan Leteurtre <tooney at via.ecp.fr <mailto:tooney at via.ecp.fr>>           
>  - original UDP code + *          Laurent Aimar <fenrir at via.ecp.fr
> <mailto: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
> <mailto:natalie.landsberg97 at gmail.com>> - AMT support + *          Wayne
> Brassem <wbrassem at rogers.com <mailto: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
> <http://amt-relay.m2icast.net/>") +
> +static int  Open (vlc_object_t *);
> +static void Close (vlc_object_t *);

Reorder the code to avoid forward declarations. Same below.

> +
> +/* 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;
> +
> +    /* Protective packet overflow buffer designed to accommodate maximum
> IPv4 UDP payload minus the anticapated MTU */

Typo.

> +    sys->overflow_block =
> block_Alloc(MAX_IPV4_UDP - sys->mtu);
> +    if( unlikely( sys->overflow_block == NULL ) )
> +        return VLC_ENOMEM;
> +
> +    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;
> +    }
> +
> +    /* Determining the multicast source and group depends on the URL
> provided */ +    /*                                                        
>                */ +    /* The address(es) in the URL can be in the form of
> IP address or FQDN    */ +    /* By calling vlc_getaaddrinfo() you get it
> in IP form either way         */ +    /*                                   
>                                     */ +    /* Case 1:
> amt://<source-ip-address>@<multicast-group-ip-address>         */ +    /*  
>                                                                      */ +  
>  /*         sys->mcastSrc = <source-ip-address>                           
> */ +    /*         sys->mcastSrcAddr = inet_pton( sys->mcastSrc )          
>       */ +    /*                                                           
>             */ +    /*         sys->mcastGroup =
> <multicast-group-ip-address>                 */ +    /*        
> sys->mcastGroupAddr = inet_pton( sys->mcastGroup )             */ +    /*  
>                                                                      */ +  
>  /* Case 2: amt://<multicast-group-ip-address>                            
> */ +    /*                                                                 
>       */ +    /*         sys->mcastSrc = MCAST_ANYCAST = "0.0.0.0"         
>             */ +    /*         sys->mcastSrcAddr = inet_pton( sys->mcastSrc
> ) = 0             */ +    /*                                               
>                         */ +    /*         sys->mcastGroup =
> <multicast-group-ip-address>                 */ +    /*        
> sys->mcastGroupAddr = inet_pton( sys->mcastGroup )             */ +    /*  
>                                                                      */ +
> +    /* If UDP port provided then assign port to stream */
> +    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 );
> +
> +    /* Initialize hints prior to call to vlc_getaddrinfo with either IP
> address or FQDN */
> +    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 );

DNS-resolving a multicast group is veeeery weird.

> +
> +    /* 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); +
> +    /* Store the binary socket representation of multicast group address */
> +    sys->mcastGroupAddr = *server_addr;
> +
> +    /* Release the allocated memory */
> +    freeaddrinfo( serverinfo );
> +    serverinfo = NULL;
> +
> +    /* Store string representation */
> +    sys->mcastGroup = strdup( ip_buffer );

As I said before, this is completely useless and not the only occurrence.

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





More information about the vlc-devel mailing list