<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>