]> git.sesse.net Git - vlc/blobdiff - modules/services_discovery/sap.c
Listen to link-local SAP announces too
[vlc] / modules / services_discovery / sap.c
index 732c9be6bf6b3d71b128776216066109e24776f6..3efddedfe5ac8198936aa530cf075f92413fd3b2 100644 (file)
@@ -49,6 +49,7 @@
 #ifdef HAVE_ZLIB_H
 #   include <zlib.h>
 #endif
+#include <net/if.h>
 
 /************************************************************************
  * Macros and definitions
 #define SAP_V4_LINK_ADDRESS     "224.0.0.255"
 #define ADD_SESSION 1
 
-#define SAP_V6_1 "FF0"
-/* Scope is inserted between them */
-#define SAP_V6_2 "::2:7FFE"
-/* See RFC3513 for list of valid scopes */
-/* FIXME: find a way to listen to link-local scope */
-static const char ipv6_scopes[] = "1456789ABCDE";
-
-
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -205,7 +198,7 @@ struct  sdp_t
 
     /* medias (well, we only support one atm) */
     unsigned            mediac;
-    struct sdp_media_t  mediav[1];
+    struct sdp_media_t *mediav;
 };
 
 struct attribute_t
@@ -277,6 +270,8 @@ struct demux_sys_t
     static inline attribute_t *MakeAttribute (const char *str);
     static const char *GetAttribute (attribute_t **tab, unsigned n, const char *name);
     static inline void FreeAttribute (attribute_t *a);
+    static const char *FindAttribute (const sdp_t *sdp, unsigned media,
+                                      const char *name);
 
     static vlc_bool_t IsSameSession( sdp_t *p_sdp1, sdp_t *p_sdp2 );
     static int InitSocket( services_discovery_t *p_sd, const char *psz_address, int i_port );
@@ -495,12 +490,25 @@ static void Run( services_discovery_t *p_sd )
     }
     if( var_CreateGetInteger( p_sd, "sap-ipv6" ) )
     {
-        char psz_address[] = SAP_V6_1"0"SAP_V6_2;
-        const char *c_scope;
+        char psz_address[NI_MAXNUMERICHOST] = "ff02::2:7ffe%";
+
+        struct if_nameindex *l = if_nameindex ();
+        if (l != NULL)
+        {
+            char *ptr = strchr (psz_address, '%') + 1;
+            for (unsigned i = 0; l[i].if_index; i++)
+            {
+                strcpy (ptr, l[i].if_name);
+                InitSocket (p_sd, psz_address, SAP_PORT);
+            }
+            if_freenameindex (l);
+        }
+        *strchr (psz_address, '%') = '\0';
 
-        for( c_scope = ipv6_scopes; *c_scope; c_scope++ )
+        static const char ipv6_scopes[] = "1456789ABCDE";
+        for (const char *c_scope = ipv6_scopes; *c_scope; c_scope++)
         {
-            psz_address[sizeof(SAP_V6_1) - 1] = *c_scope;
+            psz_address[3] = *c_scope;
             InitSocket( p_sd, psz_address, SAP_PORT );
         }
     }
@@ -792,9 +800,10 @@ sap_announce_t *CreateAnnounce( services_discovery_t *p_sd, uint16_t i_hash,
     }
 
     /* Handle group */
-    psz_value = GetAttribute( p_sap->p_sdp->pp_attributes, p_sap->p_sdp->i_attributes, "x-plgroup" );
-    if( psz_value == NULL )
-        psz_value = GetAttribute( p_sap->p_sdp->pp_attributes, p_sap->p_sdp->i_attributes, "plgroup" );
+    if (p_sap->p_sdp->mediac >= 1)
+        psz_value = FindAttribute (p_sap->p_sdp, 0, "x-plgroup");
+    else
+        psz_value = GetAttribute( p_sap->p_sdp->pp_attributes, p_sap->p_sdp->i_attributes, "x-plgroup" );
 
     if( psz_value != NULL )
     {
@@ -813,13 +822,14 @@ sap_announce_t *CreateAnnounce( services_discovery_t *p_sd, uint16_t i_hash,
     }
 
     p_item = playlist_NodeAddInput( pl_Get( p_sd ), p_input, p_child,
-                                    PLAYLIST_APPEND, PLAYLIST_END );
+                                    PLAYLIST_APPEND, PLAYLIST_END, VLC_FALSE );
     p_item->i_flags &= ~PLAYLIST_SKIP_FLAG;
     p_item->i_flags &= ~PLAYLIST_SAVE_FLAG;
     p_sap->i_item_id_cat = p_item->i_id;
 
     p_item = playlist_NodeAddInput( pl_Get( p_sd ), p_input,
-                        p_sys->p_node_one, PLAYLIST_APPEND, PLAYLIST_END );
+                        p_sys->p_node_one, PLAYLIST_APPEND, PLAYLIST_END,
+                        VLC_FALSE );
     p_item->i_flags &= ~PLAYLIST_SKIP_FLAG;
     p_item->i_flags &= ~PLAYLIST_SAVE_FLAG;
     p_sap->i_item_id_one = p_item->i_id;
@@ -843,16 +853,37 @@ static const char *FindAttribute (const sdp_t *sdp, unsigned media,
 /* Fill p_sdp->psz_uri */
 static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp )
 {
-    if (p_sdp->mediac != 1)
+    if (p_sdp->mediac == 0)
+    {
+        msg_Dbg (p_obj, "Ignoring SDP with no media");
+        return VLC_EGENERIC;
+    }
+
+    for (unsigned i = 1; i < p_sdp->mediac; i++)
+    {
+        if ((p_sdp->mediav[i].n_addr != p_sdp->mediav->n_addr)
+         || (p_sdp->mediav[i].addrlen != p_sdp->mediav->addrlen)
+         || memcmp (&p_sdp->mediav[i].addr, &p_sdp->mediav->addr,
+                    p_sdp->mediav->addrlen))
+        {
+            msg_Dbg (p_obj, "Multiple media ports not supported -> live555");
+            return VLC_EGENERIC;
+        }
+    }
+
+    if (p_sdp->mediav->n_addr != 1)
+    {
+        msg_Dbg (p_obj, "Layered encoding not supported -> live555");
         return VLC_EGENERIC;
+    }
 
     char psz_uri[1026];
     const char *host;
     int port;
 
     psz_uri[0] = '[';
-    if (vlc_getnameinfo ((struct sockaddr *)&(p_sdp->mediav[0].addr),
-                         p_sdp->mediav[0].addrlen, psz_uri + 1,
+    if (vlc_getnameinfo ((struct sockaddr *)&(p_sdp->mediav->addr),
+                         p_sdp->mediav->addrlen, psz_uri + 1,
                          sizeof (psz_uri) - 2, &port, NI_NUMERICHOST))
         return VLC_EGENERIC;
 
@@ -870,7 +901,7 @@ static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp )
         return VLC_ENOMEM;
 
     char *subtype = strchr (sdp_proto, ' ');
-    if (sdp_proto == NULL)
+    if (subtype == NULL)
     {
         msg_Dbg (p_obj, "missing SDP media subtype: %s", sdp_proto);
         p_sdp->i_media_type = 0;
@@ -897,7 +928,7 @@ static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp )
     uint8_t flags = 0;
     for (const char *proto = proto_match; *proto;)
     {
-        if (strcasecmp (proto, sdp_proto))
+        if (strcasecmp (proto, sdp_proto) == 0)
         {
             vlc_proto = proto + strlen (proto) + 1;
             flags = vlc_proto[strlen (vlc_proto) + 1];
@@ -1054,6 +1085,7 @@ static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
     memset (&glob_addr, 0, sizeof (glob_addr));
     socklen_t glob_len = 0;
     unsigned glob_count = 1;
+    int port = 0;
 
     /* TODO: use iconv and charset attribute instead of EnsureUTF8 */
     while (*psz_sdp)
@@ -1217,6 +1249,7 @@ static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
 
             /* Media description */
             case 'm':
+            media:
             {
                 expect = 'i';
                 if (cat != 'm')
@@ -1224,8 +1257,16 @@ static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
                     msg_Dbg (p_obj, "missing SDP media description");
                     goto error;
                 }
-                struct sdp_media_t *m = p_sdp->mediav + p_sdp->mediac;
+                struct sdp_media_t *m;
+                m = realloc (p_sdp->mediav, (p_sdp->mediac + 1) * sizeof (*m));
+                if (m == NULL)
+                    goto error;
+
+                p_sdp->mediav = m;
+                m += p_sdp->mediac;
+                p_sdp->mediac++;
 
+                memset (m, 0, sizeof (*m));
                 memcpy (&m->addr, &glob_addr, m->addrlen = glob_len);
                 m->n_addr = glob_count;
 
@@ -1236,7 +1277,7 @@ static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
                     msg_Dbg (p_obj, "missing SDP media port");
                     goto error;
                 }
-                int port = atoi (++data);
+                port = atoi (++data);
                 if (port <= 0 || port >= 65536)
                 {
                     msg_Dbg (p_obj, "invalid transport port %d", port);
@@ -1254,7 +1295,6 @@ static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
                 if (m->fmt == NULL)
                     goto error;
 
-                p_sdp->mediac++;
                 break;
             }
             case 'i':
@@ -1265,7 +1305,7 @@ static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
                 expect = 'b';
                 if (cat == 'c')
                 {
-                    struct sdp_media_t *m = p_sdp->mediav + p_sdp->mediac;
+                    struct sdp_media_t *m = p_sdp->mediav + p_sdp->mediac - 1;
                     if (ParseSDPConnection (data, &m->addr, &m->addrlen,
                                             &m->n_addr))
                     {
@@ -1273,6 +1313,7 @@ static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
                                  "%s", data);
                         goto error;
                     }
+                    net_SetPort ((struct sockaddr *)&m->addr, htons (port));
                     break;
                 }
             case 'b':
@@ -1297,11 +1338,7 @@ static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
                 }
 
                 if (cat == 'm')
-                {
-                    /* TODO */
-                    msg_Dbg (p_obj, "multi-media SDP not implemented -> live555");
-                    goto error;
-                }
+                    goto media;
 
                 if (cat != 'm')
                 {
@@ -1330,7 +1367,7 @@ static int InitSocket( services_discovery_t *p_sd, const char *psz_address,
     if (i_fd == -1)
         return VLC_EGENERIC;
 
-    net_StopSend( i_fd );
+    shutdown( i_fd, SHUT_WR );
     INSERT_ELEM (p_sd->p_sys->pi_fd, p_sd->p_sys->i_fd,
                  p_sd->p_sys->i_fd, i_fd);
     return VLC_SUCCESS;
@@ -1394,7 +1431,9 @@ static void FreeSDP( sdp_t *p_sdp )
         free (p_sdp->mediav[j].fmt);
         for (int i = 0; i < p_sdp->mediav[j].i_attributes; i++)
             FreeAttribute (p_sdp->mediav[j].pp_attributes[i]);
+        free (p_sdp->mediav[j].pp_attributes);
     }
+    free (p_sdp->mediav);
 
     for (int i = 0; i < p_sdp->i_attributes; i++)
         FreeAttribute (p_sdp->pp_attributes[i]);