[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