<html><head></head><body>Thomas,<br><br>I find your meta-review quite aggressive, and the more you criticize my reviews ,the more I will be pissed and the more the rougher further reviews will be.<br><br>If you don't like my reviews, you had plenty of time to do it yourself better first.<br><br>Mandatory reviews are averse to single devs as opposed to team members enough. And now you demotivate reviewers too.<br><br>Way to go to keep ruining unpaid participants motivation.<br><br><div class="gmail_quote">Le 24 septembre 2019 10:05:54 GMT+03:00, Thomas Guillem <thomas@gllm.fr> a écrit :<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<pre class="k9mail">Rémi,<br>I find your review quite aggressive. I think that it can demotivate external developers.<br>A lot of things are very obvious for both of us. We are senior developers, working on VLC since a very long time.<br>We should focus on spreading our knowledge instead of critizing like that.<br><br>Nathalie,<br>I will help you fixing the remaining part mentioned by Rémi.<br><br>On Mon, Sep 23, 2019, at 22:45, Rémi Denis-Courmont wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #729fcf; padding-left: 1ex;">Le tiistaina 17. syyskuuta 2019, 22.28.06 EEST Natalie Landsberg a écrit :<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">Changes:<br> 1. Fixed TRUE back to true. Dunno why my compiler doesn't catch this...<br> 2. Fixed parantheses for if(unlikely(inet_ntop() ) == NULL) to<br>if(unlikely(inet_ntop() == NULL) ) - "== NULL" is inside unlikely call<br>correctly<br> 3. removed GetDWBE where not used on buffer<br><br>Compiler is finally working again and I pulled latest VLC from git.<br>Hopefully it lines up with master now. ---<br> modules/access/Makefile.am | 4 +<br> modules/access/amt.c | 1434 ++++++++++++++++++++++++++++++++++++<br> 2 files changed, 1438 insertions(+)<br> create mode 100644 modules/access/amt.c<br><br>diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am<br>index 1b85e8dd18..756ca5cf59 100644<br>--- a/modules/access/Makefile.am<br>+++ b/modules/access/Makefile.am<br>@@ -379,6 +379,10 @@ libudp_plugin_la_SOURCES = access/udp.c<br> libudp_plugin_la_LIBADD = $(SOCKET_LIBS)<br> access_LTLIBRARIES += libudp_plugin.la<br><br>+libamt_plugin_la_SOURCES = access/amt.c<br>+libamt_plugin_la_LIBADD = $(SOCKET_LIBS)<br>+access_LTLIBRARIES += libamt_plugin.la<br>+<br> libunc_plugin_la_SOURCES = access/unc.c access/smb_common.h<br> libunc_plugin_la_LIBADD = -lmpr -lnetapi32<br> if HAVE_WIN32<br>diff --git a/modules/access/amt.c b/modules/access/amt.c<br>new file mode 100644<br>index 0000000000..66f15449e9<br>--- /dev/null<br>+++ b/modules/access/amt.c<br>@@ -0,0 +1,1434 @@<br>+/**<br>+ * @file amt.c<br>+ * @brief Automatic Multicast Tunneling Protocol (AMT) file for VLC media<br>player + * Allows multicast streaming when not in a multicast-enabled<br>network + * Currently IPv4 is supported, but IPv6 is not yet.<br>+ *<br>+ * Copyright (C) 2018 VLC authors and VideoLAN<br>+ * Copyright (c) Juniper Networks, Inc., 2018. All rights reserved.<br>+ *<br>+ * Authors: Christophe Massiot <massiot@via.ecp.fr> - original<br>UDP code + * Tristan Leteurtre <tooney@via.ecp.fr> -<br>original UDP code + * Laurent Aimar <fenrir@via.ecp.fr> <br> - original UDP code + * Jean-Paul Saman <jpsaman #_at_# m2x<br>dot nl> - original UDP code + * Remi Denis-Courmont <br> - original UDP code + * Natalie Landsberg<br><natalie.landsberg97@gmail.com> - AMT support + * Wayne Brassem<br><wbrassem@rogers.com> - Added FQDN support + *<br>+ * This code is licensed to you under the GNU Lesser General Public License<br>+ * version 2.1 or later. You may not use this code except in compliance<br>with + * the GNU Lesser General Public License.<br>+ * This code is not an official Juniper product.<br>+ *<br>+ * This library is free software; you can redistribute it and/or<br>+ * modify it under the terms of the GNU Lesser General Public License<br>+ * as published by the Free Software Foundation; either version 2.1<br>+ * of the License, or (at your option) any later version.<br>+ *<br>+ * This library is distributed in the hope that it will be useful,<br>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>+ * GNU Lesser General Public License for more details.<br>+ *<br>+ * You should have received a copy of the GNU Lesser General Public<br>+ * License along with this library; if not, write to the Free Software<br>+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 <br>USA +<br>***************************************************************************<br>*/ +#ifdef HAVE_CONFIG_H<br>+# include "config.h"<br>+#endif<br>+<br>+#include <errno.h><br>+#include <ctype.h><br>+#include <assert.h><br>+#ifdef HAVE_ARPA_INET_H<br>+# include <arpa/inet.h><br>+#endif<br>+<br>+#ifdef HAVE_SYS_SELECT_H<br>+# include <sys/select.h><br>+#endif<br></blockquote>It does not look like this can work.<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">+<br>+#ifdef HAVE_SYS_SOCKET_H<br>+# include <sys/socket.h><br>+#endif<br>+<br>+#include <vlc_common.h><br>+#include <vlc_demux.h><br>+#include <vlc_plugin.h><br>+#include <vlc_access.h><br>+#include <vlc_network.h><br>+#include <vlc_block.h><br>+#include <vlc_interrupt.h><br>+#include <vlc_url.h><br>+<br>+#ifdef HAVE_POLL<br>+ #include <poll.h><br>+#endif<br>+#ifdef HAVE_SYS_UIO_H<br>+ #include <sys/uio.h><br>+#endif<br>+<br>+#define BUFFER_TEXT N_("Receive buffer")<br>+#define BUFFER_LONGTEXT N_("AMT receive buffer size (bytes)" )<br>+#define TIMEOUT_TEXT N_("Native multicast timeout (sec)")<br>+#define AMT_TIMEOUT_TEXT N_("AMT timeout (sec)")<br>+#define AMT_RELAY_ADDRESS N_("AMT relay (IP address or FQDN)")<br>+#define AMT_RELAY_ADDR_LONG N_("AMT relay anycast address, or specify the<br>relay you want by address or fully qualified domain name") +#define<br>AMT_DEFAULT_RELAY N_("amt-relay.m2icast.net")<br>+<br>+/**************************************************************************<br>*** + * Various Lengths of Msgs or Hdrs<br>+<br>***************************************************************************<br>**/ +#define MAC_LEN 6 /* length of generated MAC in bytes */<br>+#define NONCE_LEN 4 /* length of nonce in bytes */<br>+<br>+#define MSG_TYPE_LEN 1 /* length of msg type */<br>+#define RELAY_QUERY_MSG_LEN 48 /* total length of relay query */<br>+#define RELAY_ADV_MSG_LEN 12 /* length of relay advertisement message<br>*/ +#define IGMP_QUERY_LEN 24 /* length of encapsulated IGMP query<br>message */ +#define IGMP_REPORT_LEN 20<br>+#define AMT_HDR_LEN 2 /* length of AMT header on a packet */<br>+#define IP_HDR_LEN 20 /* length of standard IP header */<br>+#define IP_HDR_IGMP_LEN 24 /* length of IP header with an IGMP report<br>*/ +#define UDP_HDR_LEN 8 /* length of standard UDP header */<br>+#define AMT_REQUEST_MSG_LEN 9<br>+#define AMT_DISCO_MSG_LEN 8<br>+<br>+/**************************************************************************<br>*** + * Different AMT Message Types<br>+<br>***************************************************************************<br>**/ +#define AMT_RELAY_DISCO 1 /* relay discovery */<br>+#define AMT_RELAY_ADV 2 /* relay advertisement */<br>+#define AMT_REQUEST 3 /* request */<br>+#define AMT_MEM_QUERY 4 /* membership query */<br>+#define AMT_MEM_UPD 5 /* membership update */<br>+#define AMT_MULT_DATA 6 /* multicast data */<br>+#define AMT_TEARDOWN 7 /* teardown (not currently supported) */<br>+<br>+/**************************************************************************<br>*** + * Different IGMP Message Types<br>+<br>***************************************************************************<br>**/ +#define AMT_IGMPV3_MEMBERSHIP_QUERY_TYPEID 0x11<br>+#define AMT_IGMPV3_MEMBERSHIP_REPORT_TYPEID 0x22<br>+/* IGMPv2, interoperability */<br>+#define AMT_IGMPV1_MEMBERSHIP_REPORT_TYPEID 0x12<br>+#define AMT_IGMPV2_MEMBERSHIP_REPORT_TYPEID 0x16<br>+#define AMT_IGMPV2_MEMBERSHIP_LEAVE_TYPEID 0x17<br>+<br>+#define AMT_IGMP_INCLUDE 0x01<br>+#define AMT_IGMP_EXCLUDE 0x02<br>+#define AMT_IGMP_INCLUDE_CHANGE 0x03<br>+#define AMT_IGMP_EXCLUDE_CHANGE 0x04<br>+#define AMT_IGMP_ALLOW 0x05<br>+#define AMT_IGMP_BLOCK 0x06<br>+<br>+#define MCAST_ANYCAST "0.0.0.0"<br>+#define MCAST_ALLHOSTS "224.0.0.22"<br>+#define LOCAL_LOOPBACK "127.0.0.1"<br>+#define AMT_PORT 2268<br>+<br>+#define DEFAULT_MTU (1500u - (20 + 8))<br>+#define MAX_IPV4_UDP (65535u - (20 + 8))<br>+<br>+/* IPv4 Header Format */<br>+typedef struct _amt_ip {<br>+ uint8_t ver_ihl;<br>+ uint8_t tos;<br>+ uint16_t tot_len;<br>+ uint16_t id;<br>+ uint16_t frag_off;<br>+ uint8_t ttl;<br>+ uint8_t protocol;<br>+ uint16_t check;<br>+ uint32_t srcAddr;<br>+ uint32_t destAddr;<br>+} amt_ip_t;<br>+<br>+/* IPv4 Header Format with options field */<br>+typedef struct _amt_ip_alert {<br>+ uint8_t ver_ihl;<br>+ uint8_t tos;<br>+ uint16_t tot_len;<br>+ uint16_t id;<br>+ uint16_t frag_off;<br>+ uint8_t ttl;<br>+ uint8_t protocol;<br>+ uint16_t check;<br>+ uint32_t srcAddr;<br>+ uint32_t destAddr;<br>+ uint32_t options;<br>+} amt_ip_alert_t;<br>+<br>+/* IGMPv3 Group Record Format (RFC3376) */<br>+typedef struct _amt_igmpv3_groupRecord {<br>+ uint8_t type;<br>+ uint8_t auxDatalen;<br>+ uint16_t nSrc;<br>+ uint32_t ssm;<br>+ uint32_t srcIP[1];<br>+} amt_igmpv3_groupRecord_t;<br>+<br>+/* IGMPv3 Membership Report Format (RFC3376) */<br>+typedef struct _amt_igmpv3_membership_report {<br>+ uint8_t type;<br>+ uint8_t resv;<br>+ uint16_t checksum;<br>+ uint16_t resv2;<br>+ uint16_t nGroupRecord;<br>+ amt_igmpv3_groupRecord_t grp[1];<br>+} amt_igmpv3_membership_report_t;<br>+<br>+/* IGMPv3 Membership Query Format (RFC3376) */<br>+typedef struct _amt_igmpv3_membership_query {<br>+ uint8_t type;<br>+ uint8_t max_resp_code; /* in 100ms, Max Resp Time = (mant | 0x10) <<<br>(exp + 3) */ + uint32_t checksum;<br>+ uint32_t ssmIP;<br>+ uint8_t s_qrv;<br>+ uint8_t qqic; /* in second, query Time = (mant | 0x10) <<<br>(exp + 3) */ + uint16_t nSrc;<br>+ uint32_t srcIP[1];<br>+} amt_igmpv3_membership_query_t;<br>+<br>+/* ATM Membership Update Format (RFC7450) */<br>+typedef struct _amt_membership_update_msg {<br>+ amt_ip_alert_t ipHead;<br>+ amt_igmpv3_membership_report_t memReport;<br>+} amt_membership_update_msg_t;<br>+<br>+/* AMT Functions */<br>+static int amt_sockets_init( stream_t *p_access );<br>+static void amt_send_relay_discovery_msg( stream_t *p_access, char<br>*relay_ip ); +static void amt_send_relay_request( stream_t *p_access, char<br>*relay_ip ); +static int amt_joinSSM_group( stream_t *p_access );<br>+static int amt_joinASM_group( stream_t *p_access );<br>+static int amt_leaveASM_group( stream_t *p_access );<br>+static int amt_leaveSSM_group( stream_t *p_access );<br>+static bool amt_rcv_relay_adv( stream_t *p_access );<br>+static bool amt_rcv_relay_mem_query( stream_t *p_access );<br>+static void amt_send_mem_update( stream_t *p_access, char *relay_ip, bool<br>leave ); +static bool open_amt_tunnel( stream_t *p_access );<br>+static void *amt_mem_upd( void *data );<br>+<br>+/* Struct to hold AMT state */<br>+typedef struct _access_sys_t<br>+{<br>+ char *mcastGroup;<br>+ char *mcastSrc;<br>+ char *relay;<br>+ char relayDisco[INET_ADDRSTRLEN];<br>+ block_t *overflow_block;<br>+<br>+ vlc_thread_t updateThread;<br>+ vlc_tick_t queryTime;<br>+<br>+ /* Mulicast group and source */<br>+ struct sockaddr_in mcastGroupAddr;<br>+ struct sockaddr_in mcastSrcAddr;<br>+<br>+ /* AMT relay imformation */<br>+ struct sockaddr_in relayDiscoAddr;<br>+ struct sockaddr_in relayAddr;<br>+ struct sockaddr_in stLocalAddr;<br>+ struct sockaddr_in stSvrAddr;<br>+<br>+ /* AMT Relay Membership Query data (RFC7450) */<br>+ struct relay_mem_query_msg_t {<br>+ uint32_t ulRcvedNonce;<br>+ uint8_t type;<br>+ uint8_t uchaMAC[MAC_LEN];<br>+ uint8_t uchaIGMP[IGMP_QUERY_LEN];<br>+ } relay_mem_query_msg;<br>+<br>+ /* AMT Relay Advertisement data (RFC7450) */<br>+ struct relay_adv_msg_t {<br>+ uint32_t ulRcvNonce;<br>+ uint32_t ipAddr;<br>+ uint8_t type;<br>+ } relay_adv_msg;<br>+<br>+ amt_ip_t relay_ip_hdr;<br>+ amt_igmpv3_membership_query_t relay_igmp_query;<br>+ ssize_t mtu;<br>+<br>+ uint32_t glob_ulNonce;<br>+ uint32_t ulRelayNonce;<br>+<br>+ int fd;<br>+ int sAMT;<br>+ int sQuery;<br>+ int timeout;<br>+ int amtTimeout;<br>+<br>+ bool tryAMT;<br>+ bool threadReady;<br>+} access_sys_t;<br></blockquote>Remove write-only and unused members.<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">+<br>+/* Standard open/close functions */<br>+static int Open (vlc_object_t *);<br>+static void Close (vlc_object_t *);<br>+<br>+/* Utility functions */<br>+static unsigned short get_checksum( unsigned short *buffer, int nLen );<br>+static void make_report( amt_igmpv3_membership_report_t *mr );<br>+static void make_ip_header( amt_ip_alert_t *p_ipHead );<br>+<br>+vlc_module_begin ()<br>+ set_shortname( N_("AMT" ) )<br>+ set_description( N_("AMT input") )<br>+ set_category( CAT_INPUT )<br>+ set_subcategory( SUBCAT_INPUT_ACCESS )<br>+<br>+ add_integer( "amt-timeout", 5, AMT_TIMEOUT_TEXT, NULL, true )<br>+ add_integer( "amt-native-timeout", 5, TIMEOUT_TEXT, NULL, true )<br>+ add_string( "amt-relay", AMT_DEFAULT_RELAY, AMT_RELAY_ADDRESS,<br>AMT_RELAY_ADDR_LONG, true ) +<br>+ set_capability( "access", 0 )<br>+ add_shortcut( "amt" )<br>+<br>+ set_callbacks( Open, Close )<br>+vlc_module_end ()<br>+<br>+/**************************************************************************<br>*** + * Local prototypes<br>+<br>***************************************************************************<br>**/ +static block_t *BlockUDP( stream_t *, bool * );<br>+static int Control( stream_t *, int, va_list );<br>+<br>+/**************************************************************************<br>*** + * Open: Open a connection to the multicast feed<br>+<br>***************************************************************************<br>**/ +static int Open( vlc_object_t *p_this )<br>+{<br>+ stream_t *p_access = (stream_t*) p_this;<br>+ access_sys_t *sys = NULL;<br>+ struct addrinfo hints, *serverinfo = NULL;<br>+ struct sockaddr_in *server_addr;<br>+ char *psz_name = NULL, *saveptr, *psz_strtok_r,<br>ip_buffer[INET_ADDRSTRLEN]; + int i_bind_port = 1234,<br>i_server_port = 0, VLC_ret = VLC_SUCCESS, response; + vlc_url_t <br> url;<br>+<br>+ if( p_access->b_preparsing )<br>+ return VLC_EGENERIC;<br>+<br>+ /* Allocate the structure for holding AMT info and zeroize it */<br>+ sys = vlc_obj_calloc( p_this, 1, sizeof( *sys ) );<br>+ if( unlikely( sys == NULL ) )<br>+ return VLC_ENOMEM;<br>+<br>+ /* The standard MPEG-2 transport is 188 bytes. 7 packets fit into a<br>standard 1500 byte Ethernet frame */ + sys->mtu = 7 * 188;<br>+<br>+ /* Protective packet overflow buffer designed to accommodate maximum<br>IPv4 UDP payload minus the anticapated MTU */ + sys->overflow_block =<br>block_Alloc(MAX_IPV4_UDP - sys->mtu);<br>+ if( unlikely( sys->overflow_block == NULL ) )<br>+ return VLC_ENOMEM;<br>+<br>+ p_access->p_sys = sys;<br>+<br>+ /* Set up p_access */<br>+ ACCESS_SET_CALLBACKS( NULL, BlockUDP, Control, NULL );<br>+<br>+ if( !p_access->psz_location )<br>+ return VLC_EGENERIC;<br>+<br>+ psz_name = strdup( p_access->psz_location );<br>+ if ( unlikely( psz_name == NULL ) )<br>+ return VLC_ENOMEM;<br>+<br>+ /* Parse psz_name syntax :<br>+ * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */<br>+ if( vlc_UrlParse( &url, p_access->psz_url ) != 0 )<br>+ {<br>+ msg_Err( p_access, "Invalid URL: %s", p_access->psz_url );<br>+ VLC_ret = VLC_EGENERIC;<br>+ goto cleanup;<br>+ }<br>+<br>+ /* Determining the multicast source and group depends on the URL<br>provided */ + /* <br> */ + /* The address(es) in the URL can be in the form of<br>IP address or FQDN */ + /* By calling vlc_getaaddrinfo() you get it<br>in IP form either way */ + /* <br> */ + /* Case 1:<br>amt://<source-ip-address>@<multicast-group-ip-address> */ + /* <br> */ + <br> /* sys->mcastSrc = <source-ip-address> <br>*/ + /* sys->mcastSrcAddr = inet_pton( sys->mcastSrc ) <br> */ + /* <br> */ + /* sys->mcastGroup =<br><multicast-group-ip-address> */ + /* <br>sys->mcastGroupAddr = inet_pton( sys->mcastGroup ) */ + /* <br> */ + <br> /* Case 2: amt://<multicast-group-ip-address> <br>*/ + /* <br> */ + /* sys->mcastSrc = MCAST_ANYCAST = "0.0.0.0" <br> */ + /* sys->mcastSrcAddr = inet_pton( sys->mcastSrc<br>) = 0 */ + /* <br> */ + /* sys->mcastGroup =<br><multicast-group-ip-address> */ + /* <br>sys->mcastGroupAddr = inet_pton( sys->mcastGroup ) */ + /* <br> */ +<br>+ /* If UDP port provided then assign port to stream */<br>+ if( url.i_port > 0 )<br>+ i_bind_port = url.i_port;<br>+<br>+ msg_Dbg( p_access, "Opening multicast: %s:%d local=%s:%d",<br>url.psz_host, i_server_port, url.psz_path, i_bind_port ); +<br>+ /* Initialize hints prior to call to vlc_getaddrinfo with either IP<br>address or FQDN */ + memset( &hints, 0, sizeof( hints ));<br>+ hints.ai_family = AF_INET; /* Setting to AF_UNSPEC accepts both IPv4<br>and IPv6 */ + hints.ai_socktype = SOCK_DGRAM;<br>+<br>+ /* Retrieve list of multicast addresses matching the multicast group<br>identifier */ + response = vlc_getaddrinfo( url.psz_host, AMT_PORT,<br>&hints, &serverinfo ); +<br>+ /* If an error returned print reason and exit */<br>+ if( response != 0 )<br>+ {<br>+ msg_Err( p_access, "Could not find multicast group %s, reason: %s",<br>url.psz_host, gai_strerror(response) ); + VLC_ret = VLC_EGENERIC;<br>+ goto cleanup;<br>+ }<br>+<br>+ /* Convert binary socket address to string */<br>+ server_addr = (struct sockaddr_in *) serverinfo->ai_addr;<br>+ if( unlikely( inet_ntop(AF_INET, &(server_addr->sin_addr), ip_buffer,<br>INET_ADDRSTRLEN) == NULL ) ) + {<br>+ int errConv = errno;<br>+ msg_Err(p_access, "Could not convert binary socket address to<br>string: %s", gai_strerror(errConv)); + goto cleanup;<br>+ }<br>+<br>+ /* Store the binary socket representation of multicast group address */<br>+ sys->mcastGroupAddr = *server_addr;<br>+<br>+ /* Release the allocated memory */<br>+ freeaddrinfo( serverinfo );<br>+ serverinfo = NULL;<br>+<br>+ /* Store string representation */<br>+ sys->mcastGroup = strdup( ip_buffer );<br></blockquote>You really should not do that; there are no reasons why you need to keep this <br>as a string. This is not the first time this problem is raised in this very <br>patchset, nor is this the only occurence.<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">+ if( unlikely( sys->mcastGroup == NULL ) )<br>+ {<br>+ VLC_ret = VLC_ENOMEM;<br>+ goto cleanup;<br>+ }<br>+<br>+ msg_Dbg( p_access, "Setting multicast group address to %s",<br>sys->mcastGroup); +<br>+ /* Extract the source from the URL, or the multicast group when no<br>source is provided */<br>+ if ( !( psz_strtok_r = strtok_r( psz_name, "@",<br>&saveptr ) ) ) + {<br></blockquote>DO NOT use assignment as expression unless syntactically unavoidable.<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">+ msg_Err( p_access, "Could not parse location %s", psz_name);<br>+ VLC_ret = VLC_EGENERIC;<br>+ goto cleanup;<br>+ }<br>+<br>+ /* Store the string representation */<br>+ sys->mcastSrc = strdup( psz_strtok_r );<br>+ if( unlikely( sys->mcastSrc == NULL ) )<br>+ {<br>+ VLC_ret = VLC_ENOMEM;<br>+ goto cleanup;<br>+ }<br>+<br>+ /* If strings are equal then no multicast source has been specified, so<br>try anycast */ + if( strcmp( url.psz_host, sys->mcastSrc ) == 0 )<br>+ {<br>+ free( sys->mcastSrc );<br>+ sys->mcastSrc = strdup(MCAST_ANYCAST);<br>+ sys->mcastSrcAddr.sin_addr.s_addr = 0;<br>+ msg_Dbg( p_access, "No multicast source address specified, trying<br>ASM..."); + }<br>+<br>+ /* retrieve list of source addresses matching the multicast source<br>identifier */ + response = vlc_getaddrinfo( sys->mcastSrc, AMT_PORT,<br>&hints, &serverinfo ); +<br>+ /* If an error returned print reason and exit */<br>+ if( response != 0 )<br>+ {<br>+ msg_Err( p_access, "Could not find multicast source %s, reason:<br>%s", sys->mcastSrc, gai_strerror(response) ); + VLC_ret =<br>VLC_EGENERIC;<br>+ goto cleanup;<br>+ }<br>+<br>+ /* Convert binary socket address to string */<br>+ server_addr = (struct sockaddr_in *) serverinfo->ai_addr;<br>+ if( unlikely( inet_ntop(AF_INET, &(server_addr->sin_addr), ip_buffer,<br>INET_ADDRSTRLEN) == NULL ) ) + {<br>+ int errConv = errno;<br>+ msg_Err(p_access, "Could not binary socket address to string: %s",<br>gai_strerror(errConv)); + goto cleanup;<br>+ }<br>+<br>+ /* Store the binary socket representation of multicast source address<br>*/ + sys->mcastSrcAddr = *server_addr;<br>+<br>+ /* free the original source address buffer (IP or FQDN) and assign it<br>just the IP address */ + free( sys->mcastSrc );<br>+<br>+ /* Store string representation */<br>+ sys->mcastSrc = strdup( ip_buffer );<br>+ if( unlikely( sys->mcastSrc == NULL ) )<br>+ {<br>+ VLC_ret = VLC_ENOMEM;<br>+ goto cleanup;<br>+ }<br>+<br>+ msg_Dbg( p_access, "Setting multicast source address to %s",<br>sys->mcastSrc); +<br>+ /* Pull the AMT relay address from the settings */<br>+ sys->relay = var_InheritString( p_access, "amt-relay" );<br>+ if( unlikely( sys->relay == NULL ) )<br>+ {<br>+ msg_Err( p_access, "No relay anycast or unicast address specified."<br>); + VLC_ret = VLC_EGENERIC;<br>+ goto cleanup;<br>+ }<br>+<br>+ msg_Dbg( p_access, "Addresses: mcastGroup: %s mcastSrc: %s relay: %s",<br>\ + sys->mcastGroup, sys->mcastSrc, sys->relay);<br>+<br>+ /* Native multicast file descriptor */<br>+ sys->fd = net_OpenDgram( p_access, sys->mcastGroup, i_bind_port,<br>+ sys->mcastSrc, i_server_port, IPPROTO_UDP );<br>+ if( sys->fd == -1 )<br>+ {<br>+ msg_Err( p_access, "cannot open socket" );<br>+ sys->sAMT = -1;<br>+ sys->sQuery = -1;<br>+ VLC_ret = VLC_EGENERIC;<br>+ goto cleanup;<br>+ }<br>+<br>+ sys->timeout = var_InheritInteger( p_access, "amt-native-timeout");<br>+ if( sys->timeout > 0)<br>+ sys->timeout *= 1000;<br>+<br>+ sys->amtTimeout = var_InheritInteger( p_access, "amt-timeout" );<br>+ if( sys->amtTimeout > 0)<br>+ sys->amtTimeout *= 1000;<br>+<br>+ sys->tryAMT = false;<br>+ sys->threadReady = false;<br>+<br>+cleanup: /* fall through */<br>+<br>+ /* release the allocated memory */<br>+ free( psz_name );<br>+ vlc_UrlClean( &url );<br>+ if( serverinfo )<br>+ freeaddrinfo( serverinfo );<br>+<br>+ /* if an error occurred free the memory */<br>+ if ( VLC_ret != VLC_SUCCESS )<br>+ {<br>+ msg_Dbg( p_access, "Open(): Before free( sys-> sys->Addr ) #4" );<br>+ free( sys->mcastGroup );<br>+ free( sys->mcastSrc );<br>+ }<br>+<br>+ return VLC_ret;<br>+}<br>+<br>+/**************************************************************************<br>*** + * Close: Cancel thread and free data structures<br>+<br>***************************************************************************<br>**/ +static void Close( vlc_object_t *p_this )<br>+{<br>+ stream_t *p_access = (stream_t*)p_this;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ msg_Dbg( p_access, "Closing AMT plugin" );<br>+<br>+ /* If using AMT tunneling send leave message and free the relay<br>addresses */ + if ( sys->tryAMT )<br>+ {<br>+ /* Prepare socket options */<br>+ if( sys->mcastSrcAddr.sin_addr.s_addr )<br>+ amt_leaveSSM_group( p_access );<br>+ else<br>+ amt_leaveASM_group( p_access );<br>+<br>+ /* Send IGMP leave message */<br>+ amt_send_mem_update( p_access, sys->relayDisco, true );<br>+<br>+ free( sys->relay );<br>+ }<br>+<br>+ /* If overflow block allocated then free the memory */<br>+ if( sys->overflow_block )<br>+ block_Release( sys->overflow_block );<br>+<br>+ /* If membership thread spawned cancel it */<br>+ if( sys->threadReady )<br>+ {<br>+ msg_Dbg( p_access, "Canceling IGMP membership thread" );<br>+ sys->threadReady = false;<br>+ vlc_cancel( sys->updateThread );<br>+ vlc_join( sys->updateThread, NULL );<br>+ }<br>+<br>+ if( sys->mcastGroup )<br>+ free( sys->mcastGroup );<br>+ if( sys->mcastSrc )<br>+ free( sys->mcastSrc );<br>+<br>+ net_Close( sys->fd );<br>+ if( sys->sAMT != -1 )<br>+ net_Close( sys->sAMT );<br>+ if( sys->sQuery != -1 )<br>+ net_Close( sys->sQuery );<br>+<br>+ msg_Dbg( p_access, "Exiting AMT plugin" );<br>+}<br>+<br>+/**************************************************************************<br>*** + * Control: Define stream controls<br>+<br>***************************************************************************<br>**/ +static int Control( stream_t *p_access, int i_query, va_list args ) +{<br>+ switch( i_query )<br>+ {<br>+ case STREAM_CAN_SEEK:<br>+ case STREAM_CAN_FASTSEEK:<br>+ case STREAM_CAN_PAUSE:<br>+ case STREAM_CAN_CONTROL_PACE:<br>+ *va_arg( args, bool * ) = false;<br>+ break;<br>+<br>+ case STREAM_GET_PTS_DELAY:<br>+ *va_arg( args, vlc_tick_t * ) =<br>+ VLC_TICK_FROM_MS(var_InheritInteger( p_access,<br>"network-caching" )); + break;<br>+<br>+ default:<br>+ return VLC_EGENERIC;<br>+ }<br>+<br>+ return VLC_SUCCESS;<br>+}<br>+<br>+/**************************************************************************<br>*** + * BlockUDP: Responsible for returning the multicast payload<br>+ * BlockUDP: Sections of code are based upon BlockUDP code in udp.c<br>+ *<br>+ * Default MTU based on number of MPEG-2 transports carried in a 1500 byte<br>Ethernet frame + * however the code is able to receive maximal IPv4 UDP<br>frames and then adjusts the MTU +<br>***************************************************************************<br>**/ +static block_t *BlockUDP(stream_t *p_access, bool *restrict eof)<br>+{<br>+ access_sys_t *sys = p_access->p_sys;<br>+ ssize_t len = 0, shift = 0, tunnel = IP_HDR_LEN + UDP_HDR_LEN +<br>AMT_HDR_LEN; +<br>+ /* Allocate anticipated MTU buffer for holding the UDP packet suitable<br>for native or AMT tunneled multicast */ + block_t *pkt = block_Alloc(<br>sys->mtu + tunnel );<br>+ if ( unlikely( pkt == NULL ) )<br>+ return NULL;<br>+<br>+ /* Structure initialized to hold anticipated MTU buffer along with<br>protective overflow buffer */ + struct iovec iov[] = {{<br>+ .iov_base = pkt->p_buffer,<br>+ .iov_len = sys->mtu + tunnel,<br>+ },{<br>+ .iov_base = sys->overflow_block->p_buffer,<br>+ .iov_len = sys->overflow_block->i_buffer,<br>+ }};<br>+<br>+ /* References the two element array above to be passed into recvmsg */<br>+ struct msghdr msg = {<br>+ .msg_iov = iov,<br>+ .msg_iovlen = 2,<br>+ };<br>+<br>+ struct pollfd ufd[1];<br>+<br>+ if( sys->tryAMT )<br>+ ufd[0].fd = sys->sAMT; /* AMT tunneling file descriptor */<br>+ else<br>+ ufd[0].fd = sys->fd; /* Native multicast file descriptor */<br>+ ufd[0].events = POLLIN;<br>+<br>+ switch (vlc_poll_i11e(ufd, 1, sys->timeout))<br>+ {<br>+ case 0:<br>+ if( !sys->tryAMT )<br>+ {<br>+ msg_Err(p_access, "Native multicast receive time-out");<br>+ if( !open_amt_tunnel( p_access ) )<br>+ goto error;<br>+ break;<br>+ }<br>+ else<br>+ {<br>+ *eof = true;<br>+ }<br>+ /* fall through */<br>+ case -1:<br>+ goto error;<br>+ }<br>+<br>+ /* If using AMT tunneling perform basic checks and point to beginning<br>of the payload */<br>+ if( sys->tryAMT )<br>+ {<br>+ len = recvmsg( sys->sAMT, &msg, 0 );<br></blockquote>Why do you use recvmsg()?<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">+<br>+ /* Check for the integrity of the received AMT packet */<br>+ if( len < 0 || *(pkt->p_buffer) != AMT_MULT_DATA )<br>+ goto error;<br>+<br>+ /* Set the offet to the first byte of the payload */<br>+ shift += tunnel;<br>+<br>+ /* If the length received is less than the AMT tunnel header then<br>it's truncated */ + if( len < tunnel )<br>+ {<br>+ msg_Err(p_access, "%zd bytes packet truncated (MTU was %zd)",<br>len, sys->mtu); + pkt->i_flags |= BLOCK_FLAG_CORRUPTED;<br>+ }<br>+<br>+ /* Otherwise subtract the length of the AMT encapsulation from the<br>packet received */ + else<br>+ {<br>+ len -= tunnel;<br>+ }<br>+ }<br>+ /* Otherwise pull native multicast */<br>+ else<br>+ {<br>+ len = recvmsg(sys->fd, &msg, 0);<br>+ }<br>+<br>+ /* If the payload length is greater than the MTU then the overflow<br>buffer was utilized */ + if ( unlikely( len > sys->mtu ) )<br>+ {<br>+ msg_Warn(p_access, "%zd bytes packet received (MTU was %zd),<br>adjusting mtu", len, sys->mtu); +<br>+ block_t *gather_block = sys->overflow_block;<br>+<br>+ /* Allocate a new overflow buffer based on the received payload<br>length */ + sys->overflow_block = block_Alloc(MAX_IPV4_UDP - len);<br>+<br>+ /* Set number of bytes consumed in the overflow block */<br>+ gather_block->i_buffer = len - sys->mtu;<br>+<br>+ /* Chain the anticipated packet and overflow buffers, copy into a<br>single buffer and free the chain */ + pkt->p_next = gather_block;<br>+ pkt = block_ChainGather( pkt );<br>+<br>+ /* Adjust the anticipated MTU to match the payload received */<br>+ sys->mtu = len;<br>+ }<br>+<br>+ /* Set the offset to payload start */<br>+ pkt->p_buffer += shift;<br>+ pkt->i_buffer -= shift;<br>+<br>+ return pkt;<br>+<br>+error:<br>+ block_Release( pkt );<br>+ return NULL;<br>+}<br>+<br>+/**************************************************************************<br>*** + * open_amt_tunnel: Create an AMT tunnel to the AMT relay<br>+<br>***************************************************************************<br>**/ +static bool open_amt_tunnel( stream_t *p_access )<br>+{<br>+ struct addrinfo hints, *serverinfo, *server;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ memset( &hints, 0, sizeof( hints ));<br>+ hints.ai_family = AF_INET; /* Setting to AF_UNSPEC accepts both IPv4<br>and IPv6 */ + hints.ai_socktype = SOCK_DGRAM;<br>+<br>+ msg_Dbg( p_access, "Attempting AMT to %s...", sys->relay);<br>+ sys->tryAMT = true;<br>+<br>+ /* Retrieve list of addresses matching the AMT relay */<br>+ int response = vlc_getaddrinfo( sys->relay, AMT_PORT, &hints,<br>&serverinfo ); +<br>+ /* If an error returned print reason and exit */<br>+ if( response != 0 )<br>+ {<br>+ msg_Err( p_access, "Could not find relay %s, reason: %s",<br>sys->relay, gai_strerror(response) ); + goto error;<br>+ }<br>+<br>+ /* Iterate through the list of sockets to find one that works */<br>+ for (server = serverinfo; server != NULL; server = server->ai_next)<br>+ {<br>+ struct sockaddr_in *server_addr = (struct sockaddr_in *)<br>server->ai_addr; + char relay_ip[INET_ADDRSTRLEN];<br>+<br>+ /* Convert to binary representation */<br>+ if( unlikely( inet_ntop(AF_INET, &(server_addr->sin_addr),<br>relay_ip, INET_ADDRSTRLEN) == NULL ) ) + {<br>+ int errConv = errno;<br>+ msg_Err(p_access, "Could not convert relay ip to binary<br>representation: %s", gai_strerror(errConv)); + goto error;<br>+ }<br>+<br>+ /* Store string representation */<br>+ memcpy(sys->relayDisco, relay_ip, INET_ADDRSTRLEN);<br>+ if( unlikely( sys->relayDisco == NULL ) )<br>+ {<br>+ goto error;<br>+ }<br>+<br>+ msg_Dbg( p_access, "Trying AMT Server: %s", sys->relayDisco);<br>+<br>+ /* Store the binary representation */<br>+ sys->relayDiscoAddr.sin_addr = server_addr->sin_addr;<br>+<br>+ /* If can't open socket try any others in list */<br>+ if( amt_sockets_init( p_access ) != 0 )<br>+ msg_Err( p_access, "Error initializing socket to %s", relay_ip<br>); +<br>+ /* Otherwise negotiate with AMT relay and confirm you can pull a<br>UDP packet */ + else<br>+ {<br>+ amt_send_relay_discovery_msg( p_access, relay_ip );<br>+ msg_Dbg( p_access, "Sent relay AMT discovery message to %s",<br>relay_ip ); +<br>+ if( !amt_rcv_relay_adv( p_access ) )<br>+ {<br>+ msg_Err( p_access, "Error receiving AMT relay advertisement<br>msg from %s, skipping", relay_ip ); + goto error;<br>+ }<br>+ msg_Dbg( p_access, "Received AMT relay advertisement from %s",<br>relay_ip ); +<br>+ amt_send_relay_request( p_access, relay_ip );<br>+ msg_Dbg( p_access, "Sent AMT relay request message to %s",<br>relay_ip ); +<br>+ if( !amt_rcv_relay_mem_query( p_access ) )<br>+ {<br>+ msg_Err( p_access, "Could not receive AMT relay membership<br>query from %s, reason: %s", relay_ip, vlc_strerror(errno)); + <br> goto error;<br>+ }<br>+ msg_Dbg( p_access, "Received AMT relay membership query from<br>%s", relay_ip ); +<br>+ /* If single source multicast send SSM join */<br>+ if( sys->mcastSrcAddr.sin_addr.s_addr )<br>+ {<br>+ if( amt_joinSSM_group( p_access ) != 0 )<br>+ {<br>+ msg_Err( p_access, "Error joining SSM %s",<br>vlc_strerror(errno) ); + goto error;<br>+ }<br>+ msg_Dbg( p_access, "Joined SSM src: %s group: %s",<br>sys->mcastSrc, sys->mcastGroup ); + }<br>+<br>+ /* If any source multicast send ASM join */<br>+ else {<br>+ if( amt_joinASM_group( p_access ) != 0 )<br>+ {<br>+ msg_Err( p_access, "Error joining ASM %s",<br>vlc_strerror(errno) ); + goto error;<br>+ }<br>+ msg_Dbg( p_access, "Joined ASM group: %s", sys->mcastGroup<br>); + }<br>+<br>+ bool eof=false;<br>+ block_t *pkt;<br>+<br>+ /* Confirm that you can pull a UDP packet from the socket */<br>+ if ( !(pkt = BlockUDP( p_access, &eof )) )<br>+ msg_Err( p_access, "Unable to receive UDP packet from AMT<br>relay %s for multicast group %s", relay_ip, sys->mcastGroup ); + <br>else<br>+ {<br>+ block_Release( pkt );<br>+ msg_Dbg( p_access, "Got UDP packet from multicast group %s<br>via AMT relay %s, continuing...", sys->mcastGroup, relay_ip ); + <br> break; /* found an active server sending UDP packets, so exit loop */<br>+ }<br>+ }<br>+ }<br>+<br>+ /* if server is NULL then no AMT relay is responding */<br>+ if (server == NULL)<br>+ {<br>+ msg_Err( p_access, "No AMT servers responding" );<br>+ goto error;<br>+ }<br>+<br>+ sys->queryTime = vlc_tick_now() / CLOCK_FREQ;<br>+<br>+ /* release the allocated memory */<br>+ freeaddrinfo( serverinfo );<br>+ return true;<br>+<br>+error:<br>+ sys->threadReady = false;<br>+ if( serverinfo )<br>+ freeaddrinfo( serverinfo );<br>+ return false;<br>+}<br>+<br>+/**<br>+ * Calculate checksum<br>+ * */<br>+static unsigned short get_checksum( unsigned short *buffer, int nLen )<br>+{<br>+ int nleft = nLen;<br>+ int sum = 0;<br>+ unsigned short *w = buffer;<br>+ unsigned short answer = 0;<br>+<br>+ while (nleft > 1)<br>+ {<br>+ sum += *w++;<br>+ nleft -= 2;<br>+ }<br>+ if (nleft == 1)<br>+ {<br>+ *(unsigned char*)(&answer) = *(unsigned char*)w;<br>+ sum += answer;<br>+ }<br>+ sum = (sum >> 16) + (sum & 0xffff);<br>+ answer = ~sum;<br>+ return (answer);<br>+}<br>+<br>+/**<br>+ * Make IGMP Membership report<br>+ * */<br>+static void make_report( amt_igmpv3_membership_report_t *mr )<br>+{<br>+ mr->type = AMT_IGMPV3_MEMBERSHIP_REPORT_TYPEID;<br>+ mr->resv = 0;<br>+ mr->checksum = 0;<br>+ mr->resv2 = 0;<br>+ mr->nGroupRecord = htons(1);<br>+}<br>+<br>+/**<br>+ * Make IP header<br>+ * */<br>+static void make_ip_header( amt_ip_alert_t *p_ipHead )<br>+{<br>+ p_ipHead->ver_ihl = 0x46;<br>+ p_ipHead->tos = 0xc0;<br>+ p_ipHead->tot_len = htons( IP_HDR_IGMP_LEN + IGMP_REPORT_LEN );<br>+ p_ipHead->id = 0x00;<br>+ p_ipHead->frag_off = 0x0000;<br>+ p_ipHead->ttl = 0x01;<br>+ p_ipHead->protocol = 0x02;<br>+ p_ipHead->check = 0;<br>+ p_ipHead->srcAddr = INADDR_ANY;<br>+ p_ipHead->options = 0x0000;<br>+}<br>+<br>+/** Create relay discovery socket, query socket, UDP socket and<br>+ * fills in relay anycast address for discovery<br>+ * return 0 if successful, -1 if not<br>+ */<br>+static int amt_sockets_init( stream_t *p_access )<br>+{<br>+ struct sockaddr_in rcvAddr;<br>+ access_sys_t *sys = p_access->p_sys;<br>+ memset( &rcvAddr, 0, sizeof(struct sockaddr_in) );<br>+ int enable = 0, res = 0;<br>+<br>+ /* Relay anycast address for discovery */<br>+ sys->relayDiscoAddr.sin_family = AF_INET;<br>+ sys->relayDiscoAddr.sin_port = htons( AMT_PORT );<br>+<br>+ /* create UDP socket */<br>+ sys->sAMT = vlc_socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP, true );<br>+ if( sys->sAMT == -1 )<br>+ {<br>+ msg_Err( p_access, "Failed to create UDP socket" );<br>+ goto error;<br>+ }<br>+<br>+ res = setsockopt(sys->sAMT, IPPROTO_IP, IP_PKTINFO, &enable,<br>sizeof(enable)); + if(res < 0)<br>+ {<br>+ msg_Err( p_access, "Couldn't set socket options for IPPROTO_IP,<br>IP_PKTINFO\n %s", vlc_strerror(errno)); + goto error;<br></blockquote>I am pretty damn sure that I already rejected that in previous review.<br><br><br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">+ }<br>+<br>+ res = setsockopt(sys->sAMT, SOL_SOCKET, SO_REUSEADDR, &enable,<br>sizeof(enable)); + if(res < 0)<br>+ {<br>+ msg_Err( p_access, "Couldn't make socket reusable");<br>+ goto error;<br>+ }<br>+<br>+ rcvAddr.sin_family = AF_INET;<br>+ rcvAddr.sin_port = htons( 0 );<br>+ rcvAddr.sin_addr.s_addr = INADDR_ANY;<br>+<br>+ if( bind(sys->sAMT, (struct sockaddr *)&rcvAddr, sizeof(rcvAddr) ) != 0<br>) + {<br>+ msg_Err( p_access, "Failed to bind UDP socket error: %s",<br>vlc_strerror(errno) ); + goto error;<br>+ }<br>+<br>+ sys->sQuery = vlc_socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP, true );<br>+ if( sys->sQuery == -1 )<br>+ {<br>+ msg_Err( p_access, "Failed to create query socket" );<br>+ goto error;<br>+ }<br>+<br>+ /* bind socket to local address */<br>+ sys->stLocalAddr.sin_family = AF_INET;<br>+ sys->stLocalAddr.sin_port = htons( 0 );<br>+ sys->stLocalAddr.sin_addr.s_addr = INADDR_ANY;<br>+<br>+ if( bind(sys->sQuery, (struct sockaddr *)&sys->stLocalAddr,<br>sizeof(struct sockaddr) ) != 0 ) + {<br>+ msg_Err( p_access, "Failed to bind query socket" );<br>+ goto error;<br>+ }<br>+<br>+ sys->stSvrAddr.sin_family = AF_INET;<br>+ sys->stSvrAddr.sin_port = htons( 9124 );<br>+ res = inet_pton( AF_INET, LOCAL_LOOPBACK, &sys->stSvrAddr.sin_addr );<br>+ if( res != 1 )<br>+ {<br>+ msg_Err( p_access, "Could not convert loopback address" );<br>+ goto error;<br>+ }<br>+<br>+ return 0;<br>+<br>+error:<br>+ if( sys->sAMT != -1 )<br>+ {<br>+ net_Close( sys->sAMT );<br>+ sys->sAMT = -1;<br>+ }<br>+<br>+ if( sys->sQuery != -1 )<br>+ {<br>+ net_Close( sys->sQuery );<br>+ sys->sQuery = -1;<br>+ }<br>+ return -1;<br>+}<br>+<br>+/**<br>+ * Send a relay discovery message, before 3-way handshake<br>+ * */<br>+static void amt_send_relay_discovery_msg( stream_t *p_access, char<br>*relay_ip ) +{<br>+ char chaSendBuffer[AMT_DISCO_MSG_LEN];<br>+ unsigned int ulNonce;<br>+ int nRet;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ /* initialize variables */<br>+ memset( chaSendBuffer, 0, sizeof(chaSendBuffer) );<br>+ ulNonce = 0;<br>+ nRet = 0;<br>+<br>+ /*<br>+ * create AMT discovery message format<br>+ * +---------------------------------------------------+<br>+ * | Msg Type(1Byte)| Reserved (3 byte)| nonce (4byte) |<br>+ * +---------------------------------------------------+<br>+ */<br>+<br>+ chaSendBuffer[0] = AMT_RELAY_DISCO;<br>+ chaSendBuffer[1] = 0;<br>+ chaSendBuffer[2] = 0;<br>+ chaSendBuffer[3] = 0;<br>+<br>+ /* create nonce and copy into send buffer */<br>+ srand( (unsigned int)time(NULL) );<br>+ ulNonce = htonl( rand() );<br>+ memcpy( &chaSendBuffer[4], &ulNonce, sizeof(ulNonce) );<br>+ sys->glob_ulNonce = ulNonce;<br>+<br>+ /* send it */<br>+ nRet = sendto( sys->sAMT, chaSendBuffer, sizeof(chaSendBuffer), 0,\<br>+ (struct sockaddr *)&sys->relayDiscoAddr, sizeof(struct<br>sockaddr) ); +<br>+ if( nRet < 0)<br>+ msg_Err( p_access, "Sendto failed to %s with error %d.", relay_ip,<br>errno); +}<br>+<br>+/**<br>+ * Send relay request message, stage 2 of handshake<br>+ * */<br>+static void amt_send_relay_request( stream_t *p_access, char *relay_ip )<br>+{<br>+ char chaSendBuffer[AMT_REQUEST_MSG_LEN];<br>+ uint32_t ulNonce;<br>+ int nRet;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ memset( chaSendBuffer, 0, sizeof(chaSendBuffer) );<br>+<br>+ ulNonce = 0;<br>+ nRet = 0;<br>+<br>+ /*<br>+ * create AMT request message format<br>+ * +-----------------------------------------------------------------+<br>+ * | Msg Type(1Byte)| Reserved(1byte)|P flag(1byte)|Reserved (2 byte)|<br>+ * +-----------------------------------------------------------------+<br>+ * | nonce (4byte) |<br>+ * +-----------------------------------------------------------------+<br>+ *<br>+ * The P flag is set to indicate which group membership protocol the<br>+ * gateway wishes the relay to use in the Membership Query response:<br>+<br>+ * Value Meaning<br>+<br>+ * 0 The relay MUST respond with a Membership Query message that<br>+ * contains an IPv4 packet carrying an IGMPv3 General Query<br>+ * message.<br>+ * 1 The relay MUST respond with a Membership Query message that<br>+ * contains an IPv6 packet carrying an MLDv2 General Query<br>+ * message.<br>+ *<br>+ */<br>+<br>+ chaSendBuffer[0] = AMT_REQUEST;<br>+ chaSendBuffer[1] = 0;<br>+ chaSendBuffer[2] = 0;<br>+ chaSendBuffer[3] = 0;<br>+<br>+ ulNonce = sys->glob_ulNonce;<br>+ memcpy( &chaSendBuffer[4], &ulNonce, sizeof(uint32_t) );<br>+<br>+ nRet = send( sys->sAMT, chaSendBuffer, sizeof(chaSendBuffer), 0 );<br>+<br>+ if( nRet < 0 )<br>+ msg_Err(p_access, "Error sending relay request to %s error: %s",<br>relay_ip, vlc_strerror(errno) ); +}<br>+<br>+/*<br>+* create AMT request message format<br>+*<br>+--------------------------------------------------------------------------<br>--------+ +* | Msg Type(1 byte)| Reserved (1 byte)| MAC (6 byte)| nonce (4<br>byte) | IGMP packet | +*<br>+--------------------------------------------------------------------------<br>--------+ +*/<br>+static void amt_send_mem_update( stream_t *p_access, char *relay_ip, bool<br>leave) +{<br>+ int sendBufSize = IP_HDR_IGMP_LEN + MAC_LEN + NONCE_LEN +<br>AMT_HDR_LEN; + char pSendBuffer[ sendBufSize + IGMP_REPORT_LEN<br>];<br>+ uint32_t ulNonce = 0;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ memset( pSendBuffer, 0, sizeof(pSendBuffer) );<br>+<br>+ pSendBuffer[0] = AMT_MEM_UPD;<br>+<br>+ /* copy relay MAC response */<br>+ memcpy( &pSendBuffer[2], sys->relay_mem_query_msg.uchaMAC, MAC_LEN );<br>+<br>+ /* copy nonce */<br>+ ulNonce = ntohl(sys->glob_ulNonce);<br>+ memcpy( &pSendBuffer[8], &ulNonce, NONCE_LEN );<br>+<br>+ /* make IP header for IGMP packet */<br>+ amt_ip_alert_t p_ipHead;<br>+ memset( &p_ipHead, 0, IP_HDR_IGMP_LEN );<br>+ make_ip_header( &p_ipHead );<br>+<br>+ struct sockaddr_in temp;<br>+ int res = inet_pton( AF_INET, MCAST_ALLHOSTS, &(temp.sin_addr) );<br>+ if( res != 1 )<br>+ {<br>+ msg_Err(p_access, "Could not convert all hosts multicast address:<br>%s", gai_strerror(errno) ); + return;<br>+ }<br>+ p_ipHead.destAddr = temp.sin_addr.s_addr;<br>+ p_ipHead.check = get_checksum( (unsigned short*)&p_ipHead,<br>IP_HDR_IGMP_LEN ); +<br>+ amt_igmpv3_groupRecord_t groupRcd;<br>+ groupRcd.auxDatalen = 0;<br>+ groupRcd.ssm = sys->mcastGroupAddr.sin_addr.s_addr;<br>+<br>+ if( sys->mcastSrcAddr.sin_addr.s_addr )<br>+ {<br>+ groupRcd.type = leave ? AMT_IGMP_BLOCK:AMT_IGMP_INCLUDE;<br>+ groupRcd.nSrc = htons(1);<br>+ groupRcd.srcIP[0] = sys->mcastSrcAddr.sin_addr.s_addr;<br>+<br>+ } else {<br>+ groupRcd.type = leave ?<br>AMT_IGMP_INCLUDE_CHANGE:AMT_IGMP_EXCLUDE_CHANGE; + groupRcd.nSrc =<br>htons(0);<br>+ }<br>+<br>+ /* make IGMP membership report */<br>+ amt_igmpv3_membership_report_t p_igmpMemRep;<br>+ make_report( &p_igmpMemRep );<br>+<br>+ memcpy(&p_igmpMemRep.grp[0], &groupRcd, (int)sizeof(groupRcd) );<br>+ p_igmpMemRep.checksum = get_checksum( (unsigned short*)&p_igmpMemRep,<br>IGMP_REPORT_LEN ); +<br>+ amt_membership_update_msg_t memUpdateMsg;<br>+ memset(&memUpdateMsg, 0, sizeof(memUpdateMsg));<br>+ memcpy(&memUpdateMsg.ipHead, &p_ipHead, sizeof(p_ipHead) );<br>+ memcpy(&memUpdateMsg.memReport, &p_igmpMemRep, sizeof(p_igmpMemRep) );<br>+<br>+ memcpy( &pSendBuffer[12], &memUpdateMsg, sizeof(memUpdateMsg) );<br>+<br>+ send( sys->sAMT, pSendBuffer, sizeof(pSendBuffer), 0 );<br>+<br>+ msg_Dbg( p_access, "AMT relay membership report sent to %s", relay_ip<br>); +}<br>+<br>+/**<br>+ * Receive relay advertisement message<br>+ *<br>+ *<br>+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ * | V=0 |Type=2 | Reserved |<br>+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ * | Discovery Nonce |<br>+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ * | |<br>+ * ~ Relay Address (IPv4 or IPv6) ~<br>+ * | |<br>+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ * */<br>+static bool amt_rcv_relay_adv( stream_t *p_access )<br>+{<br>+ char pkt[RELAY_ADV_MSG_LEN];<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ memset( pkt, 0, RELAY_ADV_MSG_LEN );<br>+<br>+ struct pollfd ufd[1];<br>+<br>+ ufd[0].fd = sys->sAMT;<br>+ ufd[0].events = POLLIN;<br>+<br>+ switch( vlc_poll_i11e(ufd, 1, sys->timeout) )<br>+ {<br>+ case 0:<br>+ msg_Err(p_access, "AMT relay advertisement receive time-out");<br>+ /* fall through */<br>+ case -1:<br>+ return false;<br>+ }<br>+<br>+ struct sockaddr temp;<br>+ uint32_t temp_size = sizeof( struct sockaddr );<br>+ ssize_t len = recvfrom( sys->sAMT, &pkt, RELAY_ADV_MSG_LEN, 0, &temp,<br>&temp_size ); +<br>+ if (len < 0)<br>+ {<br>+ msg_Err(p_access, "Received message length less than zero");<br>+ return false;<br>+ }<br>+<br>+ memcpy( &sys->relay_adv_msg.type, &pkt[0], MSG_TYPE_LEN );<br>+ if( sys->relay_adv_msg.type != AMT_RELAY_ADV )<br>+ {<br>+ msg_Err( p_access, "Received message not an AMT relay<br>advertisement, ignoring. "); + return false;<br>+ }<br>+<br>+ memcpy( &sys->relay_adv_msg.ulRcvNonce, &pkt[NONCE_LEN], NONCE_LEN );<br>+ if( sys->glob_ulNonce != sys->relay_adv_msg.ulRcvNonce )<br>+ {<br>+ msg_Err( p_access, "Discovery nonces differ! currNonce:%x rcvd%x",<br>sys->glob_ulNonce, ntohl(sys->relay_adv_msg.ulRcvNonce) ); + return<br>false;<br>+ }<br>+<br>+ memcpy( &sys->relay_adv_msg.ipAddr, &pkt[8], 4 );<br>+<br>+ memset( &sys->relayAddr, 0, sizeof(sys->relayAddr) );<br>+ sys->relayAddr.sin_family = AF_INET;<br>+ sys->relayAddr.sin_addr.s_addr = sys->relay_adv_msg.ipAddr;<br>+ sys->relayAddr.sin_port = htons( AMT_PORT );<br>+<br>+ int nRet = connect( sys->sAMT, (struct sockaddr *)&sys->relayAddr,<br>sizeof(sys->relayAddr) );<br>+ if( nRet < 0 )<br>+ {<br>+ msg_Err( p_access, "Error connecting AMT UDP socket: %s",<br>vlc_strerror(errno) ); + return false;<br>+ }<br>+<br>+ return true;<br>+}<br>+<br>+/**<br>+ * Receive relay membership query message<br>+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ | V=0 |Type=4 | Reserved |L|G| Response MAC |<br>+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +<br>+ | |<br>+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ | Request Nonce |<br>+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ | |<br>+ | Encapsulated General Query Message |<br>+ ~ IPv4:IGMPv3(Membership Query) ~<br>+ | IPv6:MLDv2(Listener Query) |<br>+ | |<br>+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ | Gateway Port Number | |<br>+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +<br>+ | |<br>+ + +<br>+ | Gateway IP Address (IPv4 or IPv6) |<br>+ + +<br>+ | |<br>+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ | |<br>+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>+ */<br>+static bool amt_rcv_relay_mem_query( stream_t *p_access )<br>+{<br>+ char pkt[RELAY_QUERY_MSG_LEN];<br>+ memset( pkt, 0, RELAY_QUERY_MSG_LEN );<br>+ struct pollfd ufd[1];<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ ufd[0].fd = sys->sAMT;<br>+ ufd[0].events = POLLIN;<br>+<br>+ switch( vlc_poll_i11e(ufd, 1, sys->timeout) )<br>+ {<br>+ case 0:<br>+ msg_Err(p_access, "AMT relay membership query receive<br>time-out"); + /* fall through */<br>+ case -1:<br>+ return false;<br>+ }<br>+<br>+ ssize_t len = recv( sys->sAMT, &pkt, RELAY_QUERY_MSG_LEN, 0 );<br>+<br>+ if (len < 0)<br>+ {<br>+ msg_Err(p_access, "length less than zero");<br>+ return false;<br>+ }<br>+<br>+ memcpy( &sys->relay_mem_query_msg.type, &pkt[0], MSG_TYPE_LEN );<br></blockquote>Potentially undefined read. Ditto below.<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">+ /* pkt[1] is reserved */<br>+ memcpy( &sys->relay_mem_query_msg.uchaMAC[0], &pkt[AMT_HDR_LEN],<br>MAC_LEN ); + memcpy( &sys->relay_mem_query_msg.ulRcvedNonce,<br>&pkt[AMT_HDR_LEN + MAC_LEN], NONCE_LEN )<br>+ if(<br>sys->relay_mem_query_msg.ulRcvedNonce != sys->glob_ulNonce )<br>+ {<br>+ msg_Warn( p_access, "Nonces are different rcvd: %x glob: %x",<br>sys->relay_mem_query_msg.ulRcvedNonce, sys->glob_ulNonce );<br>+ return<br>false;<br>+ }<br>+<br>+ size_t shift = AMT_HDR_LEN + MAC_LEN + NONCE_LEN;<br>+ memcpy( &sys->relay_ip_hdr, &pkt[shift], IP_HDR_IGMP_LEN );<br>+<br>+ shift += IP_HDR_IGMP_LEN;<br>+ sys->relay_igmp_query.type = pkt[shift];<br>+ shift++; assert( shift < RELAY_QUERY_MSG_LEN);<br>+ sys->relay_igmp_query.max_resp_code = pkt[shift];<br>+ shift++; assert( shift < RELAY_QUERY_MSG_LEN);<br>+ memcpy( &sys->relay_igmp_query.checksum, &pkt[shift], 2 );<br>+ shift += 2; assert( shift < RELAY_QUERY_MSG_LEN);<br>+ memcpy( &sys->relay_igmp_query.ssmIP, &pkt[shift], 4 );<br>+ shift += 4; assert( shift < RELAY_QUERY_MSG_LEN);<br>+ sys->relay_igmp_query.s_qrv = pkt[shift];<br>+ shift++; assert( shift < RELAY_QUERY_MSG_LEN);<br>+ if( pkt[shift] == 0 )<br>+ sys->relay_igmp_query.qqic = 125;<br>+ else<br>+ sys->relay_igmp_query.qqic = pkt[shift];<br>+<br>+ shift++; assert( shift < RELAY_QUERY_MSG_LEN);<br>+ memcpy( &sys->relay_igmp_query.nSrc, &pkt[shift], 2 );<br>+ /* if a membership thread exists cancel it */<br>+ if( sys->threadReady )<br>+ {<br>+ msg_Dbg( p_access, "Canceling existing AMT relay membership update<br>thread"); +<br>+ sys->threadReady = false;<br>+ vlc_cancel( sys->updateThread );<br>+ vlc_join( sys->updateThread, NULL );<br>+ }<br>+<br>+ msg_Dbg( p_access, "Spawning AMT relay membership update thread");<br>+<br>+ if( vlc_clone( &sys->updateThread, amt_mem_upd, p_access,<br>VLC_THREAD_PRIORITY_LOW) ) + {<br>+ msg_Err( p_access, "Could not create AMT relay membership update<br>thread" ); + return false;<br>+ }<br>+<br>+ /* set theadReady to true, thread will send periodic membership updates<br>until false */ + sys->threadReady = true;<br>+ return true;<br>+}<br>+<br>+/**<br>+ * Join SSM group based on input addresses, or use the defaults<br>+ * */<br>+static int amt_joinSSM_group( stream_t *p_access )<br>+{<br>+ struct ip_mreq_source imr;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ imr.imr_multiaddr.s_addr = sys->mcastGroupAddr.sin_addr.s_addr;<br>+ imr.imr_sourceaddr.s_addr = sys->mcastSrcAddr.sin_addr.s_addr;<br>+ imr.imr_interface.s_addr = INADDR_ANY;<br>+<br>+ return setsockopt( sys->sAMT, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,<br>(char *)&imr, sizeof(imr) ); +}<br>+<br>+static int amt_joinASM_group( stream_t *p_access )<br>+{<br>+ struct ip_mreq imr;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ imr.imr_multiaddr.s_addr = sys->mcastGroupAddr.sin_addr.s_addr;<br>+ imr.imr_interface.s_addr = INADDR_ANY;<br>+<br>+ return setsockopt( sys->sAMT, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char<br>*)&imr, sizeof(imr) ); +}<br>+<br>+/**<br>+ * Leave SSM group that was joined earlier.<br>+ * */<br>+static int amt_leaveSSM_group( stream_t *p_access )<br>+{<br>+ struct ip_mreq_source imr;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ imr.imr_multiaddr.s_addr = sys->mcastGroupAddr.sin_addr.s_addr;<br>+ imr.imr_sourceaddr.s_addr = sys->mcastSrcAddr.sin_addr.s_addr;<br>+ imr.imr_interface.s_addr = INADDR_ANY;<br>+<br>+ return setsockopt( sys->sAMT, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,<br>(char *)&imr, sizeof(imr) ); +}<br>+<br>+/**<br>+ * Leave ASM group that was joined earlier.<br>+ * */<br>+static int amt_leaveASM_group( stream_t *p_access )<br>+{<br>+ struct ip_mreq imr;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ imr.imr_multiaddr.s_addr = sys->mcastGroupAddr.sin_addr.s_addr;<br>+ imr.imr_interface.s_addr = INADDR_ANY;<br>+<br>+ return setsockopt( sys->sAMT, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char<br>*)&imr, sizeof(imr) ); +}<br>+<br>+/* A thread is spawned since IGMP membership updates need to issued<br>periodically in order to continue to receive multicast */ +/* Simple timers<br>are not suitable for this requirement since the parent is otherwise<br>occupied in receiving UDP packet flow */<br></blockquote>That looks like complete nonsense.<br><br><blockquote class="gmail_quote" style="margin: 0pt 0pt 1ex 0.8ex; border-left: 1px solid #ad7fa8; padding-left: 1ex;">+static void *amt_mem_upd( void<br>*data )<br>+{<br>+ stream_t *p_access = (stream_t*) data;<br>+ access_sys_t *sys = p_access->p_sys;<br>+<br>+ msg_Dbg( p_access, "AMT relay membership update thread started" );<br>+<br>+ /* thread sends periodic AMT membership updates until Close() which<br>terminates thread */ + while ( true )<br>+ {<br>+ amt_send_mem_update( p_access, sys->relayDisco, false );<br>+ vlc_tick_sleep( (vlc_tick_t)sys->relay_igmp_query.qqic * CLOCK_FREQ<br>); + }<br>+<br>+ return NULL;<br>+}<br></blockquote>-- <br>Rémi Denis-Courmont<br><a href="http://www.remlab.net/">http://www.remlab.net/</a><hr>vlc-devel mailing list<br>To unsubscribe or modify your subscription options:<br><a href="https://mailman.videolan.org/listinfo/vlc-devel">https://mailman.videolan.org/listinfo/vlc-devel</a><br></blockquote><hr>vlc-devel mailing list<br>To unsubscribe or modify your subscription options:<br><a href="https://mailman.videolan.org/listinfo/vlc-devel">https://mailman.videolan.org/listinfo/vlc-devel</a></pre></blockquote></div><br>-- <br>Envoyé de mon appareil Android avec Courriel K-9 Mail. Veuillez excuser ma brièveté.</body></html>