sap.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:48k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * sap.c :  SAP interface module
  3.  *****************************************************************************
  4.  * Copyright (C) 2004-2005 the VideoLAN team
  5.  * Copyright © 2007 Rémi Denis-Courmont
  6.  * $Id: 803ffb7224069f7f08ed2e187c57939ef02e2cdb $
  7.  *
  8.  * Authors: Clément Stenac <zorglub@videolan.org>
  9.  *          Rémi Denis-Courmont
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Includes
  27.  *****************************************************************************/
  28. #ifdef HAVE_CONFIG_H
  29. # include "config.h"
  30. #endif
  31. #include <vlc_common.h>
  32. #include <vlc_plugin.h>
  33. #include <assert.h>
  34. #include <vlc_demux.h>
  35. #include <vlc_services_discovery.h>
  36. #include <vlc_network.h>
  37. #include <vlc_charset.h>
  38. #include <ctype.h>
  39. #include <errno.h>
  40. #ifdef HAVE_UNISTD_H
  41. #    include <unistd.h>
  42. #endif
  43. #ifdef HAVE_SYS_TIME_H
  44. #    include <sys/time.h>
  45. #endif
  46. #ifdef HAVE_POLL
  47. # include <poll.h>
  48. #endif
  49. #ifdef HAVE_ZLIB_H
  50. #   include <zlib.h>
  51. #endif
  52. #ifndef WIN32
  53. #   include <net/if.h>
  54. #endif
  55. /************************************************************************
  56.  * Macros and definitions
  57.  ************************************************************************/
  58. #define MAX_LINE_LENGTH 256
  59. /* SAP is always on that port */
  60. #define SAP_PORT 9875
  61. /* Global-scope SAP address */
  62. #define SAP_V4_GLOBAL_ADDRESS   "224.2.127.254"
  63. /* Organization-local SAP address */
  64. #define SAP_V4_ORG_ADDRESS      "239.195.255.255"
  65. /* Local (smallest non-link-local scope) SAP address */
  66. #define SAP_V4_LOCAL_ADDRESS    "239.255.255.255"
  67. /* Link-local SAP address */
  68. #define SAP_V4_LINK_ADDRESS     "224.0.0.255"
  69. #define ADD_SESSION 1
  70. /*****************************************************************************
  71.  * Module descriptor
  72.  *****************************************************************************/
  73. #define SAP_ADDR_TEXT N_( "SAP multicast address" )
  74. #define SAP_ADDR_LONGTEXT N_( "The SAP module normally chooses itself the " 
  75.                               "right addresses to listen to. However, you " 
  76.                               "can specify a specific address." )
  77. #define SAP_IPV4_TEXT N_( "IPv4 SAP" )
  78. #define SAP_IPV4_LONGTEXT N_( 
  79.       "Listen to IPv4 announcements on the standard addresses." )
  80. #define SAP_IPV6_TEXT N_( "IPv6 SAP" )
  81. #define SAP_IPV6_LONGTEXT N_( 
  82.       "Listen to IPv6 announcements on the standard addresses." )
  83. #define SAP_SCOPE_TEXT N_( "IPv6 SAP scope" )
  84. #define SAP_SCOPE_LONGTEXT N_( 
  85.        "Scope for IPv6 announcements (default is 8)." )
  86. #define SAP_TIMEOUT_TEXT N_( "SAP timeout (seconds)" )
  87. #define SAP_TIMEOUT_LONGTEXT N_( 
  88.        "Delay after which SAP items get deleted if no new announcement " 
  89.        "is received." )
  90. #define SAP_PARSE_TEXT N_( "Try to parse the announce" )
  91. #define SAP_PARSE_LONGTEXT N_( 
  92.        "This enables actual parsing of the announces by the SAP module. " 
  93.        "Otherwise, all announcements are parsed by the "live555" " 
  94.        "(RTP/RTSP) module." )
  95. #define SAP_STRICT_TEXT N_( "SAP Strict mode" )
  96. #define SAP_STRICT_LONGTEXT N_( 
  97.        "When this is set, the SAP parser will discard some non-compliant " 
  98.        "announcements." )
  99. #define SAP_CACHE_TEXT N_("Use SAP cache")
  100. #define SAP_CACHE_LONGTEXT N_( 
  101.        "This enables a SAP caching mechanism. " 
  102.        "This will result in lower SAP startup time, but you could end up " 
  103.        "with items corresponding to legacy streams." )
  104. /* Callbacks */
  105.     static int  Open ( vlc_object_t * );
  106.     static void Close( vlc_object_t * );
  107.     static int  OpenDemux ( vlc_object_t * );
  108.     static void CloseDemux ( vlc_object_t * );
  109. vlc_module_begin ()
  110.     set_shortname( N_("SAP"))
  111.     set_description( N_("SAP Announcements") )
  112.     set_category( CAT_PLAYLIST )
  113.     set_subcategory( SUBCAT_PLAYLIST_SD )
  114.     add_string( "sap-addr", NULL, NULL,
  115.                 SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, true )
  116.     add_bool( "sap-ipv4", 1 , NULL,
  117.                SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, true )
  118.     add_bool( "sap-ipv6", 1 , NULL,
  119.               SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, true )
  120.     add_integer( "sap-timeout", 1800, NULL,
  121.                  SAP_TIMEOUT_TEXT, SAP_TIMEOUT_LONGTEXT, true )
  122.     add_bool( "sap-parse", 1 , NULL,
  123.                SAP_PARSE_TEXT,SAP_PARSE_LONGTEXT, true )
  124.     add_bool( "sap-strict", 0 , NULL,
  125.                SAP_STRICT_TEXT,SAP_STRICT_LONGTEXT, true )
  126. #if 0
  127.     add_bool( "sap-cache", 0 , NULL,
  128.                SAP_CACHE_TEXT,SAP_CACHE_LONGTEXT, true )
  129. #endif
  130.     add_obsolete_bool( "sap-timeshift" ) /* Redumdant since 1.0.0 */
  131.     set_capability( "services_discovery", 0 )
  132.     set_callbacks( Open, Close )
  133.     add_submodule ()
  134.         set_description( N_("SDP Descriptions parser") )
  135.         add_shortcut( "sdp" )
  136.         set_capability( "demux", 51 )
  137.         set_callbacks( OpenDemux, CloseDemux )
  138. vlc_module_end ()
  139. /*****************************************************************************
  140.  * Local structures
  141.  *****************************************************************************/
  142. typedef struct sdp_t sdp_t;
  143. typedef struct attribute_t attribute_t;
  144. typedef struct sap_announce_t sap_announce_t;
  145. struct sdp_media_t
  146. {
  147.     struct sdp_t           *parent;
  148.     char                   *fmt;
  149.     struct sockaddr_storage addr;
  150.     socklen_t               addrlen;
  151.     unsigned                n_addr;
  152.     int           i_attributes;
  153.     attribute_t  **pp_attributes;
  154. };
  155. /* The structure that contains sdp information */
  156. struct  sdp_t
  157. {
  158.     const char *psz_sdp;
  159.     /* o field */
  160.     char     username[64];
  161.     uint64_t session_id;
  162.     uint64_t session_version;
  163.     unsigned orig_ip_version;
  164.     char     orig_host[1024];
  165.     /* s= field */
  166.     char *psz_sessionname;
  167.     /* old cruft */
  168.     /* "computed" URI */
  169.     char *psz_uri;
  170.     int           i_media_type;
  171.     unsigned rtcp_port;
  172.     /* a= global attributes */
  173.     int           i_attributes;
  174.     attribute_t  **pp_attributes;
  175.     /* medias (well, we only support one atm) */
  176.     unsigned            mediac;
  177.     struct sdp_media_t *mediav;
  178. };
  179. struct attribute_t
  180. {
  181.     const char *value;
  182.     char name[];
  183. };
  184. struct sap_announce_t
  185. {
  186.     mtime_t i_last;
  187.     mtime_t i_period;
  188.     uint8_t i_period_trust;
  189.     uint16_t    i_hash;
  190.     uint32_t    i_source[4];
  191.     /* SAP annnounces must only contain one SDP */
  192.     sdp_t       *p_sdp;
  193.     input_item_t * p_item;
  194. };
  195. struct services_discovery_sys_t
  196. {
  197.     vlc_thread_t thread;
  198.     /* Socket descriptors */
  199.     int i_fd;
  200.     int *pi_fd;
  201.     /* Table of announces */
  202.     int i_announces;
  203.     struct sap_announce_t **pp_announces;
  204.     /* Modes */
  205.     bool  b_strict;
  206.     bool  b_parse;
  207.     int i_timeout;
  208. };
  209. struct demux_sys_t
  210. {
  211.     sdp_t *p_sdp;
  212. };
  213. /*****************************************************************************
  214.  * Local prototypes
  215.  *****************************************************************************/
  216. /* Main functions */
  217.     static int Demux( demux_t *p_demux );
  218.     static int Control( demux_t *, int, va_list );
  219.     static void *Run  ( void *p_sd );
  220. /* Main parsing functions */
  221.     static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp );
  222.     static int ParseSAP( services_discovery_t *p_sd, const uint8_t *p_buffer, size_t i_read );
  223.     static sdp_t *ParseSDP (vlc_object_t *p_sd, const char *psz_sdp);
  224.     static sap_announce_t *CreateAnnounce( services_discovery_t *, uint16_t, sdp_t * );
  225.     static int RemoveAnnounce( services_discovery_t *p_sd, sap_announce_t *p_announce );
  226. /* Helper functions */
  227.     static inline attribute_t *MakeAttribute (const char *str);
  228.     static const char *GetAttribute (attribute_t **tab, unsigned n, const char *name);
  229.     static inline void FreeAttribute (attribute_t *a);
  230.     static const char *FindAttribute (const sdp_t *sdp, unsigned media,
  231.                                       const char *name);
  232.     static bool IsSameSession( sdp_t *p_sdp1, sdp_t *p_sdp2 );
  233.     static int InitSocket( services_discovery_t *p_sd, const char *psz_address, int i_port );
  234.     static int Decompress( const unsigned char *psz_src, unsigned char **_dst, int i_len );
  235.     static void FreeSDP( sdp_t *p_sdp );
  236. static inline int min_int( int a, int b )
  237. {
  238.     return a > b ? b : a;
  239. }
  240. static bool IsWellKnownPayload (int type)
  241. {
  242.     switch (type)
  243.     {   /* Should be in sync with modules/demux/rtp.c */
  244.         case  0: /* PCMU/8000 */
  245.         case  3:
  246.         case  8: /* PCMA/8000 */
  247.         case 10: /* L16/44100/2 */
  248.         case 11: /* L16/44100 */
  249.         case 12:
  250.         case 14: /* MPA/90000 */
  251.         case 32: /* MPV/90000 */
  252.         case 33: /* MP2/90000 */
  253.             return true;
  254.    }
  255.    return false;
  256. }
  257. /*****************************************************************************
  258.  * Open: initialize and create stuff
  259.  *****************************************************************************/
  260. static int Open( vlc_object_t *p_this )
  261. {
  262.     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
  263.     services_discovery_sys_t *p_sys  = (services_discovery_sys_t *)
  264.                                 malloc( sizeof( services_discovery_sys_t ) );
  265.     if( !p_sys )
  266.         return VLC_ENOMEM;
  267.     p_sys->i_timeout = var_CreateGetInteger( p_sd, "sap-timeout" );
  268.     p_sd->p_sys  = p_sys;
  269.     p_sys->pi_fd = NULL;
  270.     p_sys->i_fd = 0;
  271.     p_sys->b_strict = var_CreateGetInteger( p_sd, "sap-strict");
  272.     p_sys->b_parse = var_CreateGetInteger( p_sd, "sap-parse" );
  273. #if 0
  274.     if( var_CreateGetInteger( p_sd, "sap-cache" ) )
  275.     {
  276.         CacheLoad( p_sd );
  277.     }
  278. #endif
  279.     p_sys->i_announces = 0;
  280.     p_sys->pp_announces = NULL;
  281.     /* TODO: create sockets here, and fix racy sockets table */
  282.     if (vlc_clone (&p_sys->thread, Run, p_sd, VLC_THREAD_PRIORITY_LOW))
  283.     {
  284.         free (p_sys);
  285.         return VLC_EGENERIC;
  286.     }
  287.     return VLC_SUCCESS;
  288. }
  289. /*****************************************************************************
  290.  * OpenDemux: initialize and create stuff
  291.  *****************************************************************************/
  292. static int OpenDemux( vlc_object_t *p_this )
  293. {
  294.     demux_t *p_demux = (demux_t *)p_this;
  295.     const uint8_t *p_peek;
  296.     char *psz_sdp = NULL;
  297.     sdp_t *p_sdp = NULL;
  298.     int errval = VLC_EGENERIC;
  299.     size_t i_len;
  300.     if( !var_CreateGetInteger( p_demux, "sap-parse" ) )
  301.     {
  302.         /* We want livedotcom module to parse this SDP file */
  303.         return VLC_EGENERIC;
  304.     }
  305.     assert( p_demux->s ); /* this is NOT an access_demux */
  306.     /* Probe for SDP */
  307.     if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 )
  308.         return VLC_EGENERIC;
  309.     if( memcmp( p_peek, "v=0rno=", 7 ) && memcmp( p_peek, "v=0no=", 6 ) )
  310.         return VLC_EGENERIC;
  311.     /* Gather the complete sdp file */
  312.     for( i_len = 0, psz_sdp = NULL; i_len < 65536; )
  313.     {
  314.         const int i_read_max = 1024;
  315.         char *psz_sdp_new = realloc( psz_sdp, i_len + i_read_max );
  316.         size_t i_read;
  317.         if( psz_sdp_new == NULL )
  318.         {
  319.             errval = VLC_ENOMEM;
  320.             goto error;
  321.         }
  322.         psz_sdp = psz_sdp_new;
  323.         i_read = stream_Read( p_demux->s, &psz_sdp[i_len], i_read_max );
  324.         if( (int)i_read < 0 )
  325.         {
  326.             msg_Err( p_demux, "cannot read SDP" );
  327.             goto error;
  328.         }
  329.         i_len += i_read;
  330.         psz_sdp[i_len] = '';
  331.         if( (int)i_read < i_read_max )
  332.             break; // EOF
  333.     }
  334.     p_sdp = ParseSDP( VLC_OBJECT(p_demux), psz_sdp );
  335.     if( !p_sdp )
  336.     {
  337.         msg_Warn( p_demux, "invalid SDP");
  338.         goto error;
  339.     }
  340.     if( ParseConnection( VLC_OBJECT( p_demux ), p_sdp ) )
  341.     {
  342.         p_sdp->psz_uri = NULL;
  343.     }
  344.     if (!IsWellKnownPayload (p_sdp->i_media_type))
  345.         goto error;
  346.     if( p_sdp->psz_uri == NULL ) goto error;
  347.     p_demux->p_sys = (demux_sys_t *)malloc( sizeof(demux_sys_t) );
  348.     p_demux->p_sys->p_sdp = p_sdp;
  349.     p_demux->pf_control = Control;
  350.     p_demux->pf_demux = Demux;
  351.     FREENULL( psz_sdp );
  352.     return VLC_SUCCESS;
  353. error:
  354.     FREENULL( psz_sdp );
  355.     if( p_sdp ) FreeSDP( p_sdp ); p_sdp = NULL;
  356.     stream_Seek( p_demux->s, 0 );
  357.     return errval;
  358. }
  359. /*****************************************************************************
  360.  * Close:
  361.  *****************************************************************************/
  362. static void Close( vlc_object_t *p_this )
  363. {
  364.     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
  365.     services_discovery_sys_t    *p_sys  = p_sd->p_sys;
  366.     int i;
  367.     vlc_cancel (p_sys->thread);
  368.     vlc_join (p_sys->thread, NULL);
  369.     for( i = p_sys->i_fd-1 ; i >= 0 ; i-- )
  370.     {
  371.         net_Close( p_sys->pi_fd[i] );
  372.     }
  373.     FREENULL( p_sys->pi_fd );
  374. #if 0
  375.     if( config_GetInt( p_sd, "sap-cache" ) )
  376.     {
  377.         CacheSave( p_sd );
  378.     }
  379. #endif
  380.     for( i = p_sys->i_announces  - 1;  i>= 0; i-- )
  381.     {
  382.         RemoveAnnounce( p_sd, p_sys->pp_announces[i] );
  383.     }
  384.     FREENULL( p_sys->pp_announces );
  385.     free( p_sys );
  386. }
  387. /*****************************************************************************
  388.  * CloseDemux: Close the demuxer
  389.  *****************************************************************************/
  390. static void CloseDemux( vlc_object_t *p_this )
  391. {
  392.     demux_t *p_demux = (demux_t *)p_this;
  393.     if( p_demux->p_sys )
  394.     {
  395.         if( p_demux->p_sys->p_sdp ) { FreeSDP( p_demux->p_sys->p_sdp ); p_demux->p_sys->p_sdp = NULL; }
  396.         free( p_demux->p_sys );
  397.     }
  398. }
  399. /*****************************************************************************
  400.  * Run: main SAP thread
  401.  *****************************************************************************
  402.  * Listens to SAP packets, and sends them to packet_handle
  403.  *****************************************************************************/
  404. #define MAX_SAP_BUFFER 5000
  405. static void *Run( void *data )
  406. {
  407.     services_discovery_t *p_sd = data;
  408.     char *psz_addr;
  409.     int i;
  410.     int timeout = -1;
  411.     int canc = vlc_savecancel ();
  412.     /* Braindead Winsock DNS resolver will get stuck over 2 seconds per failed
  413.      * DNS queries, even if the DNS server returns an error with milliseconds.
  414.      * You don't want to know why the bug (as of XP SP2) wasn't fixed since
  415.      * Winsock 1.1 from Windows 95, if not Windows 3.1.
  416.      * Anyway, to avoid a 30 seconds delay for failed IPv6 socket creation,
  417.      * we have to open sockets in Run() rather than Open(). */
  418.     if( var_CreateGetInteger( p_sd, "sap-ipv4" ) )
  419.     {
  420.         InitSocket( p_sd, SAP_V4_GLOBAL_ADDRESS, SAP_PORT );
  421.         InitSocket( p_sd, SAP_V4_ORG_ADDRESS, SAP_PORT );
  422.         InitSocket( p_sd, SAP_V4_LOCAL_ADDRESS, SAP_PORT );
  423.         InitSocket( p_sd, SAP_V4_LINK_ADDRESS, SAP_PORT );
  424.     }
  425.     if( var_CreateGetInteger( p_sd, "sap-ipv6" ) )
  426.     {
  427.         char psz_address[NI_MAXNUMERICHOST] = "ff02::2:7ffe%";
  428. #ifndef WIN32
  429.         struct if_nameindex *l = if_nameindex ();
  430.         if (l != NULL)
  431.         {
  432.             char *ptr = strchr (psz_address, '%') + 1;
  433.             for (unsigned i = 0; l[i].if_index; i++)
  434.             {
  435.                 strcpy (ptr, l[i].if_name);
  436.                 InitSocket (p_sd, psz_address, SAP_PORT);
  437.             }
  438.             if_freenameindex (l);
  439.         }
  440. #else
  441.         /* this is the Winsock2 equivalant of SIOCGIFCONF on BSD stacks,
  442.            which if_nameindex uses internally anyway */
  443.         // first create a dummy socket to pin down the protocol family
  444.         SOCKET s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  445.         if( s != INVALID_SOCKET )
  446.         {
  447.             INTERFACE_INFO ifaces[10]; // Assume there will be no more than 10 IP interfaces
  448.             size_t len = sizeof(ifaces);
  449.             if( SOCKET_ERROR != WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0, &ifaces, len, &len, NULL, NULL) )
  450.             {
  451.                 unsigned ifcount = len/sizeof(INTERFACE_INFO);
  452.                 char *ptr = strchr (psz_address, '%') + 1;
  453.                 for(unsigned i = 1; i<=ifcount; ++i )
  454.                 {
  455.                     // append link-local zone identifier
  456.                     sprintf(ptr, "%d", i);
  457.                 }
  458.             }
  459.             closesocket(s);
  460.         }
  461. #endif
  462.         *strchr (psz_address, '%') = '';
  463.         static const char ipv6_scopes[] = "1456789ABCDE";
  464.         for (const char *c_scope = ipv6_scopes; *c_scope; c_scope++)
  465.         {
  466.             psz_address[3] = *c_scope;
  467.             InitSocket( p_sd, psz_address, SAP_PORT );
  468.         }
  469.     }
  470.     psz_addr = var_CreateGetString( p_sd, "sap-addr" );
  471.     if( psz_addr && *psz_addr )
  472.         InitSocket( p_sd, psz_addr, SAP_PORT );
  473.     free( psz_addr );
  474.     if( p_sd->p_sys->i_fd == 0 )
  475.     {
  476.         msg_Err( p_sd, "unable to listen on any address" );
  477.         return NULL;
  478.     }
  479.     /* read SAP packets */
  480.     for (;;)
  481.     {
  482.         vlc_restorecancel (canc);
  483.         unsigned n = p_sd->p_sys->i_fd;
  484.         struct pollfd ufd[n];
  485.         for (unsigned i = 0; i < n; i++)
  486.         {
  487.             ufd[i].fd = p_sd->p_sys->pi_fd[i];
  488.             ufd[i].events = POLLIN;
  489.             ufd[i].revents = 0;
  490.         }
  491.         int val = poll (ufd, n, timeout);
  492.         canc = vlc_savecancel ();
  493.         if (val > 0)
  494.         {
  495.             for (unsigned i = 0; i < n; i++)
  496.             {
  497.                 if (ufd[i].revents)
  498.                 {
  499.                     uint8_t p_buffer[MAX_SAP_BUFFER+1];
  500.                     ssize_t i_read;
  501.                     i_read = net_Read (p_sd, ufd[i].fd, NULL, p_buffer,
  502.                                        MAX_SAP_BUFFER, false);
  503.                     if (i_read < 0)
  504.                         msg_Warn (p_sd, "receive error: %m");
  505.                     if (i_read > 6)
  506.                     {
  507.                         /* Parse the packet */
  508.                         p_buffer[i_read] = '';
  509.                         ParseSAP (p_sd, p_buffer, i_read);
  510.                     }
  511.                 }
  512.             }
  513.         }
  514.         mtime_t now = mdate();
  515.         /* A 1 hour timeout correspong to the RFC Implicit timeout.
  516.          * This timeout is tuned in the following loop. */
  517.         timeout = 1000 * 60 * 60;
  518.         /* Check for items that need deletion */
  519.         for( i = 0; i < p_sd->p_sys->i_announces; i++ )
  520.         {
  521.             mtime_t i_timeout = ( mtime_t ) 1000000 * p_sd->p_sys->i_timeout;
  522.             sap_announce_t * p_announce = p_sd->p_sys->pp_announces[i];
  523.             mtime_t i_last_period = now - p_announce->i_last;
  524.             /* Remove the annoucement, if the last announcement was 1 hour ago
  525.              * or if the last packet emitted was 3 times the average time
  526.              * between two packets */
  527.             if( ( p_announce->i_period_trust > 5 && i_last_period > 3 * p_announce->i_period ) ||
  528.                 i_last_period > i_timeout )
  529.             {
  530.                 RemoveAnnounce( p_sd, p_announce );
  531.             }
  532.             else
  533.             {
  534.                 /* Compute next timeout */
  535.                 if( p_announce->i_period_trust > 5 )
  536.                     timeout = min_int((3 * p_announce->i_period - i_last_period) / 1000, timeout);
  537.                 timeout = min_int((i_timeout - i_last_period)/1000, timeout);
  538.             }
  539.         }
  540.         if( !p_sd->p_sys->i_announces )
  541.             timeout = -1; /* We can safely poll indefinitly. */
  542.         else if( timeout < 200 )
  543.             timeout = 200; /* Don't wakeup too fast. */
  544.     }
  545.     assert (0);
  546. }
  547. /**********************************************************************
  548.  * Demux: reads and demuxes data packets
  549.  * Return -1 if error, 0 if EOF, 1 else
  550.  **********************************************************************/
  551. static int Demux( demux_t *p_demux )
  552. {
  553.     sdp_t *p_sdp = p_demux->p_sys->p_sdp;
  554.     input_thread_t *p_input;
  555.     input_item_t *p_parent_input;
  556.     p_input = (input_thread_t *)vlc_object_find( p_demux, VLC_OBJECT_INPUT,
  557.                                                  FIND_PARENT );
  558.     assert( p_input );
  559.     if( !p_input )
  560.     {
  561.         msg_Err( p_demux, "parent input could not be found" );
  562.         return VLC_EGENERIC;
  563.     }
  564.     /* This item hasn't been held by input_GetItem
  565.      * don't release it */
  566.     p_parent_input = input_GetItem( p_input );
  567.     input_item_SetURI( p_parent_input, p_sdp->psz_uri );
  568.     input_item_SetName( p_parent_input, p_sdp->psz_sessionname );
  569.     if( p_sdp->rtcp_port )
  570.     {
  571.         char *rtcp;
  572.         if( asprintf( &rtcp, ":rtcp-port=%u", p_sdp->rtcp_port ) != -1 )
  573.         {
  574.             input_item_AddOption( p_parent_input, rtcp, VLC_INPUT_OPTION_TRUSTED );
  575.             free( rtcp );
  576.         }
  577.     }
  578.     vlc_mutex_lock( &p_parent_input->lock );
  579.     p_parent_input->i_type = ITEM_TYPE_NET;
  580.     vlc_mutex_unlock( &p_parent_input->lock );
  581.     vlc_object_release( p_input );
  582.     return VLC_SUCCESS;
  583. }
  584. static int Control( demux_t *p_demux, int i_query, va_list args )
  585. {
  586.     VLC_UNUSED(p_demux); VLC_UNUSED(i_query); VLC_UNUSED(args);
  587.     return VLC_EGENERIC;
  588. }
  589. /**************************************************************
  590.  * Local functions
  591.  **************************************************************/
  592. /* i_read is at least > 6 */
  593. static int ParseSAP( services_discovery_t *p_sd, const uint8_t *buf,
  594.                      size_t len )
  595. {
  596.     int i;
  597.     const char          *psz_sdp;
  598.     const uint8_t *end = buf + len;
  599.     sdp_t               *p_sdp;
  600.     assert (buf[len] == '');
  601.     if (len < 4)
  602.         return VLC_EGENERIC;
  603.     uint8_t flags = buf[0];
  604.     /* First, check the sap announce is correct */
  605.     if ((flags >> 5) != 1)
  606.         return VLC_EGENERIC;
  607.     bool b_ipv6 = (flags & 0x10) != 0;
  608.     bool b_need_delete = (flags & 0x04) != 0;
  609.     if (flags & 0x02)
  610.     {
  611.         msg_Dbg( p_sd, "encrypted packet, unsupported" );
  612.         return VLC_EGENERIC;
  613.     }
  614.     bool b_compressed = (flags & 0x01) != 0;
  615.     uint16_t i_hash = U16_AT (buf + 2);
  616.     if( p_sd->p_sys->b_strict && i_hash == 0 )
  617.     {
  618.         msg_Dbg( p_sd, "strict mode, discarding announce with null id hash");
  619.         return VLC_EGENERIC;
  620.     }
  621.     // Skips source address and auth data
  622.     buf += 4 + (b_ipv6 ? 16 : 4) + buf[1];
  623.     if (buf > end)
  624.         return VLC_EGENERIC;
  625.     uint8_t *decomp = NULL;
  626.     if( b_compressed )
  627.     {
  628.         int newsize = Decompress (buf, &decomp, end - buf);
  629.         if (newsize < 0)
  630.         {
  631.             msg_Dbg( p_sd, "decompression of SAP packet failed" );
  632.             return VLC_EGENERIC;
  633.         }
  634.         decomp = realloc (decomp, newsize + 1);
  635.         decomp[newsize] = '';
  636.         psz_sdp = (const char *)decomp;
  637.         len = newsize;
  638.     }
  639.     else
  640.     {
  641.         psz_sdp = (const char *)buf;
  642.         len = end - buf;
  643.     }
  644.     /* len is a strlen here here. both buf and decomp are len+1 where the 1 should be a  */
  645.     assert( psz_sdp[len] == '');
  646.     /* Skip payload type */
  647.     /* SAPv1 has implicit "application/sdp" payload type: first line is v=0 */
  648.     if (strncmp (psz_sdp, "v=0", 3))
  649.     {
  650.         size_t clen = strlen (psz_sdp) + 1;
  651.         if (strcmp (psz_sdp, "application/sdp"))
  652.         {
  653.             msg_Dbg (p_sd, "unsupported content type: %s", psz_sdp);
  654.             return VLC_EGENERIC;
  655.         }
  656.         // skips content type
  657.         if (len <= clen)
  658.             return VLC_EGENERIC;
  659.         len -= clen;
  660.         psz_sdp += clen;
  661.     }
  662.     /* Parse SDP info */
  663.     p_sdp = ParseSDP( VLC_OBJECT(p_sd), psz_sdp );
  664.     if( p_sdp == NULL )
  665.         return VLC_EGENERIC;
  666.     p_sdp->psz_sdp = psz_sdp;
  667.     /* Decide whether we should add a playlist item for this SDP */
  668.     /* Parse connection information (c= & m= ) */
  669.     if( ParseConnection( VLC_OBJECT(p_sd), p_sdp ) )
  670.         p_sdp->psz_uri = NULL;
  671.     /* Multi-media or no-parse -> pass to LIVE.COM */
  672.     if( !IsWellKnownPayload( p_sdp->i_media_type ) || !p_sd->p_sys->b_parse )
  673.     {
  674.         free( p_sdp->psz_uri );
  675.         if (asprintf( &p_sdp->psz_uri, "sdp://%s", p_sdp->psz_sdp ) == -1)
  676.             p_sdp->psz_uri = NULL;
  677.     }
  678.     if( p_sdp->psz_uri == NULL )
  679.     {
  680.         FreeSDP( p_sdp );
  681.         return VLC_EGENERIC;
  682.     }
  683.     for( i = 0 ; i< p_sd->p_sys->i_announces ; i++ )
  684.     {
  685.         sap_announce_t * p_announce = p_sd->p_sys->pp_announces[i];
  686.         /* FIXME: slow */
  687.         /* FIXME: we create a new announce each time the sdp changes */
  688.         if( IsSameSession( p_announce->p_sdp, p_sdp ) )
  689.         {
  690.             /* We don't support delete announcement as they can easily
  691.              * Be used to highjack an announcement by a third party.
  692.              * Intead we cleverly implement Implicit Announcement removal.
  693.              *
  694.              * if( b_need_delete )
  695.              *    RemoveAnnounce( p_sd, p_sd->p_sys->pp_announces[i]);
  696.              * else
  697.              */
  698.             if( !b_need_delete )
  699.             {
  700.                 /* No need to go after six, as we start to trust the
  701.                  * average period at six */
  702.                 if( p_announce->i_period_trust <= 5 )
  703.                     p_announce->i_period_trust++;
  704.                 /* Compute the average period */
  705.                 mtime_t now = mdate();
  706.                 p_announce->i_period = (p_announce->i_period + (now - p_announce->i_last)) / 2;
  707.                 p_announce->i_last = now;
  708.             }
  709.             FreeSDP( p_sdp ); p_sdp = NULL;
  710.             return VLC_SUCCESS;
  711.         }
  712.     }
  713.     CreateAnnounce( p_sd, i_hash, p_sdp );
  714.     FREENULL (decomp);
  715.     return VLC_SUCCESS;
  716. }
  717. sap_announce_t *CreateAnnounce( services_discovery_t *p_sd, uint16_t i_hash,
  718.                                 sdp_t *p_sdp )
  719. {
  720.     input_item_t *p_input;
  721.     const char *psz_value;
  722.     sap_announce_t *p_sap = (sap_announce_t *)malloc(
  723.                                         sizeof(sap_announce_t ) );
  724.     services_discovery_sys_t *p_sys;
  725.     if( p_sap == NULL )
  726.         return NULL;
  727.     p_sys = p_sd->p_sys;
  728.     p_sap->i_last = mdate();
  729.     p_sap->i_period = 0;
  730.     p_sap->i_period_trust = 0;
  731.     p_sap->i_hash = i_hash;
  732.     p_sap->p_sdp = p_sdp;
  733.     /* Released in RemoveAnnounce */
  734.     p_input = input_item_NewWithType( VLC_OBJECT(p_sd),
  735.                                      p_sap->p_sdp->psz_uri,
  736.                                      p_sdp->psz_sessionname,
  737.                                      0, NULL, 0, -1, ITEM_TYPE_NET );
  738.     p_sap->p_item = p_input;
  739.     if( !p_input )
  740.     {
  741.         free( p_sap );
  742.         return NULL;
  743.     }
  744.     if( p_sdp->rtcp_port )
  745.     {
  746.         char *rtcp;
  747.         if( asprintf( &rtcp, ":rtcp-port=%u", p_sdp->rtcp_port ) != -1 )
  748.         {
  749.             input_item_AddOption( p_input, rtcp, VLC_INPUT_OPTION_TRUSTED );
  750.             free( rtcp );
  751.         }
  752.     }
  753.     psz_value = GetAttribute( p_sap->p_sdp->pp_attributes, p_sap->p_sdp->i_attributes, "tool" );
  754.     if( psz_value != NULL )
  755.     {
  756.         input_item_AddInfo( p_input, _("Session"), _("Tool"), "%s", psz_value );
  757.     }
  758.     if( strcmp( p_sdp->username, "-" ) )
  759.     {
  760.         input_item_AddInfo( p_input, _("Session"), _("User"), "%s",
  761.                            p_sdp->username );
  762.     }
  763.     /* Handle group */
  764.     if (p_sap->p_sdp->mediac >= 1)
  765.         psz_value = FindAttribute (p_sap->p_sdp, 0, "x-plgroup");
  766.     else
  767.         psz_value = GetAttribute( p_sap->p_sdp->pp_attributes, p_sap->p_sdp->i_attributes, "x-plgroup" );
  768.     services_discovery_AddItem( p_sd, p_input, psz_value /* category name */ );
  769.     TAB_APPEND( p_sys->i_announces, p_sys->pp_announces, p_sap );
  770.     return p_sap;
  771. }
  772. static const char *FindAttribute (const sdp_t *sdp, unsigned media,
  773.                                   const char *name)
  774. {
  775.     /* Look for media attribute, and fallback to session */
  776.     const char *attr = GetAttribute (sdp->mediav[media].pp_attributes,
  777.                                      sdp->mediav[media].i_attributes, name);
  778.     if (attr == NULL)
  779.         attr = GetAttribute (sdp->pp_attributes, sdp->i_attributes, name);
  780.     return attr;
  781. }
  782. /* Fill p_sdp->psz_uri */
  783. static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp )
  784. {
  785.     if (p_sdp->mediac == 0)
  786.     {
  787.         msg_Dbg (p_obj, "Ignoring SDP with no media");
  788.         return VLC_EGENERIC;
  789.     }
  790.     for (unsigned i = 1; i < p_sdp->mediac; i++)
  791.     {
  792.         if ((p_sdp->mediav[i].n_addr != p_sdp->mediav->n_addr)
  793.          || (p_sdp->mediav[i].addrlen != p_sdp->mediav->addrlen)
  794.          || memcmp (&p_sdp->mediav[i].addr, &p_sdp->mediav->addr,
  795.                     p_sdp->mediav->addrlen))
  796.         {
  797.             msg_Dbg (p_obj, "Multiple media ports not supported -> live555");
  798.             return VLC_EGENERIC;
  799.         }
  800.     }
  801.     if (p_sdp->mediav->n_addr != 1)
  802.     {
  803.         msg_Dbg (p_obj, "Layered encoding not supported -> live555");
  804.         return VLC_EGENERIC;
  805.     }
  806.     char psz_uri[1026];
  807.     const char *host;
  808.     int port;
  809.     psz_uri[0] = '[';
  810.     if (vlc_getnameinfo ((struct sockaddr *)&(p_sdp->mediav->addr),
  811.                          p_sdp->mediav->addrlen, psz_uri + 1,
  812.                          sizeof (psz_uri) - 2, &port, NI_NUMERICHOST))
  813.         return VLC_EGENERIC;
  814.     if (strchr (psz_uri + 1, ':'))
  815.     {
  816.         host = psz_uri;
  817.         strcat (psz_uri, "]");
  818.     }
  819.     else
  820.         host = psz_uri + 1;
  821.     /* Parse m= field */
  822.     char *sdp_proto = strdup (p_sdp->mediav[0].fmt);
  823.     if (sdp_proto == NULL)
  824.         return VLC_ENOMEM;
  825.     char *subtype = strchr (sdp_proto, ' ');
  826.     if (subtype == NULL)
  827.     {
  828.         msg_Dbg (p_obj, "missing SDP media subtype: %s", sdp_proto);
  829.         free (sdp_proto);
  830.         return VLC_EGENERIC;
  831.     }
  832.     else
  833.     {
  834.         *subtype++ = '';
  835.         /* FIXME: check for multiple payload types in RTP/AVP case.
  836.          * FIXME: check for "mpeg" subtype in raw udp case. */
  837.         if (!strcasecmp (sdp_proto, "udp"))
  838.             p_sdp->i_media_type = 33;
  839.         else
  840.             p_sdp->i_media_type = atoi (subtype);
  841.     }
  842.     /* RTP protocol, nul, VLC shortcut, nul, flags byte as follow:
  843.      * 0x1: Connection-Oriented media. */
  844.     static const char proto_match[] =
  845.         "udp"             "udp"
  846.         "RTP/AVP"         "rtp"
  847.         "UDPLite/RTP/AVP" "udplite"
  848.         "DCCP/RTP/AVP"    "dccp1"
  849.         "TCP/RTP/AVP"     "rtptcp1"
  850.         "";
  851.     const char *vlc_proto = NULL;
  852.     uint8_t flags = 0;
  853.     for (const char *proto = proto_match; *proto;)
  854.     {
  855.         if (strcasecmp (proto, sdp_proto) == 0)
  856.         {
  857.             vlc_proto = proto + strlen (proto) + 1;
  858.             flags = vlc_proto[strlen (vlc_proto) + 1];
  859.             break;
  860.         }
  861.         proto += strlen (proto) + 1;
  862.         proto += strlen (proto) + 2;
  863.     }
  864.     free (sdp_proto);
  865.     if (vlc_proto == NULL)
  866.     {
  867.         msg_Dbg (p_obj, "unknown SDP media protocol: %s",
  868.                  p_sdp->mediav[0].fmt);
  869.         return VLC_EGENERIC;
  870.     }
  871.     if (!strcmp (vlc_proto, "udp") || FindAttribute (p_sdp, 0, "rtcp-mux"))
  872.         p_sdp->rtcp_port = 0;
  873.     else
  874.     {
  875.         const char *rtcp = FindAttribute (p_sdp, 0, "rtcp");
  876.         if (rtcp)
  877.             p_sdp->rtcp_port = atoi (rtcp);
  878.         else
  879.         if (port & 1) /* odd port -> RTCP; next even port -> RTP */
  880.             p_sdp->rtcp_port = port++;
  881.         else /* even port -> RTP; next odd port -> RTCP */
  882.             p_sdp->rtcp_port = port + 1;
  883.     }
  884.     if (flags & 1)
  885.     {
  886.         /* Connection-oriented media */
  887.         const char *setup = FindAttribute (p_sdp, 0, "setup");
  888.         if (setup == NULL)
  889.             setup = "active"; /* default value */
  890.         if (strcmp (setup, "actpass") && strcmp (setup, "passive"))
  891.         {
  892.             msg_Dbg (p_obj, "unsupported COMEDIA mode: %s", setup);
  893.             return VLC_EGENERIC;
  894.         }
  895.         if (asprintf (&p_sdp->psz_uri, "%s://%s:%d", vlc_proto,
  896.                       host, port) == -1)
  897.             return VLC_ENOMEM;
  898.     }
  899.     else
  900.     {
  901.         /* Non-connected (normally multicast) media */
  902.         char psz_source[258] = "";
  903.         const char *sfilter = FindAttribute (p_sdp, 0, "source-filter");
  904.         if (sfilter != NULL)
  905.         {
  906.             char psz_source_ip[256];
  907.             unsigned ipv;
  908.             if (sscanf (sfilter, " incl IN IP%u %*s %255s ", &ipv,
  909.                         psz_source_ip) == 2)
  910.             {
  911.                 /* According to RFC4570, FQDNs can be used for source-filters,
  912.                  * but -seriously- this is impractical */
  913.                 switch (ipv)
  914.                 {
  915. #ifdef AF_INET6
  916.                     case 6:
  917.                     {
  918.                         struct in6_addr addr;
  919.                         if ((inet_pton (AF_INET6, psz_source_ip, &addr) > 0)
  920.                         && (inet_ntop (AF_INET6, &addr, psz_source + 1,
  921.                                         sizeof (psz_source) - 2) != NULL))
  922.                         {
  923.                             psz_source[0] = '[';
  924.                             psz_source[strlen (psz_source)] = ']';
  925.                         }
  926.                         break;
  927.                     }
  928. #endif
  929.                     case 4:
  930.                     {
  931.                         struct in_addr addr;
  932.                         if ((inet_pton (AF_INET, psz_source_ip, &addr) > 0)
  933.                         && (inet_ntop (AF_INET, &addr, psz_source,
  934.                                         sizeof (psz_source)) == NULL))
  935.                             *psz_source = '';
  936.                         break;
  937.                     }
  938.                 }
  939.             }
  940.         }
  941.         if (asprintf (&p_sdp->psz_uri, "%s://%s@%s:%i", vlc_proto, psz_source,
  942.                      host, port) == -1)
  943.             return VLC_ENOMEM;
  944.     }
  945.     return VLC_SUCCESS;
  946. }
  947. static int ParseSDPConnection (const char *str, struct sockaddr_storage *addr,
  948.                                socklen_t *addrlen, unsigned *number)
  949. {
  950.     char host[60];
  951.     unsigned fam, n1, n2;
  952.     int res = sscanf (str, "IN IP%u %59[^/]/%u/%u", &fam, host, &n1, &n2);
  953.     if (res < 2)
  954.         return -1;
  955.     switch (fam)
  956.     {
  957. #ifdef AF_INET6
  958.         case 6:
  959.             addr->ss_family = AF_INET6;
  960. # ifdef HAVE_SA_LEN
  961.             addr->ss_len =
  962. # endif
  963.            *addrlen = sizeof (struct sockaddr_in6);
  964.             if (inet_pton (AF_INET6, host,
  965.                            &((struct sockaddr_in6 *)addr)->sin6_addr) <= 0)
  966.                 return -1;
  967.             *number = (res >= 3) ? n1 : 1;
  968.             break;
  969. #endif
  970.         case 4:
  971.             addr->ss_family = AF_INET;
  972. # ifdef HAVE_SA_LEN
  973.             addr->ss_len =
  974. # endif
  975.            *addrlen = sizeof (struct sockaddr_in);
  976.             if (inet_pton (AF_INET, host,
  977.                            &((struct sockaddr_in *)addr)->sin_addr) <= 0)
  978.                 return -1;
  979.             *number = (res >= 4) ? n2 : 1;
  980.             break;
  981.         default:
  982.             return -1;
  983.     }
  984.     return 0;
  985. }
  986. /***********************************************************************
  987.  * ParseSDP : SDP parsing
  988.  * *********************************************************************
  989.  * Validate SDP and parse all fields
  990.  ***********************************************************************/
  991. static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp)
  992. {
  993.     if( psz_sdp == NULL )
  994.         return NULL;
  995.     sdp_t *p_sdp = calloc (1, sizeof (*p_sdp));
  996.     if (p_sdp == NULL)
  997.         return NULL;
  998.     char expect = 'V';
  999.     struct sockaddr_storage glob_addr;
  1000.     memset (&glob_addr, 0, sizeof (glob_addr));
  1001.     socklen_t glob_len = 0;
  1002.     unsigned glob_count = 1;
  1003.     int port = 0;
  1004.     /* TODO: use iconv and charset attribute instead of EnsureUTF8 */
  1005.     while (*psz_sdp)
  1006.     {
  1007.         /* Extract one line */
  1008.         char *eol = strchr (psz_sdp, 'n');
  1009.         size_t linelen = eol ? (size_t)(eol - psz_sdp) : strlen (psz_sdp);
  1010.         char line[linelen + 1];
  1011.         memcpy (line, psz_sdp, linelen);
  1012.         line[linelen] = '';
  1013.         psz_sdp += linelen + 1;
  1014.         /* Remove carriage return if present */
  1015.         eol = strchr (line, 'r');
  1016.         if (eol != NULL)
  1017.         {
  1018.             linelen = eol - line;
  1019.             line[linelen] = '';
  1020.         }
  1021.         /* Validate line */
  1022.         char cat = line[0], *data = line + 2;
  1023.         if (!cat || (strchr ("vosiuepcbtrzkam", cat) == NULL))
  1024.         {
  1025.             /* MUST ignore SDP with unknown line type */
  1026.             msg_Dbg (p_obj, "unknown SDP line type: 0x%02x", (int)cat);
  1027.             goto error;
  1028.         }
  1029.         if (line[1] != '=')
  1030.         {
  1031.             msg_Dbg (p_obj, "invalid SDP line: %s", line);
  1032.             goto error;
  1033.         }
  1034.         assert (linelen >= 2);
  1035.         /* SDP parsing state machine
  1036.          * We INTERNALLY use uppercase for session, lowercase for media
  1037.          */
  1038.         switch (expect)
  1039.         {
  1040.             /* Session description */
  1041.             case 'V':
  1042.                 expect = 'O';
  1043.                 if (cat != 'v')
  1044.                 {
  1045.                     msg_Dbg (p_obj, "missing SDP version");
  1046.                     goto error;
  1047.                 }
  1048.                 if (strcmp (data, "0"))
  1049.                 {
  1050.                     msg_Dbg (p_obj, "unknown SDP version: %s", data);
  1051.                     goto error;
  1052.                 }
  1053.                 break;
  1054.             case 'O':
  1055.             {
  1056.                 expect = 'S';
  1057.                 if (cat != 'o')
  1058.                 {
  1059.                     msg_Dbg (p_obj, "missing SDP originator");
  1060.                     goto error;
  1061.                 }
  1062.                 if ((sscanf (data, "%63s %"PRIu64" %"PRIu64" IN IP%u %1023s",
  1063.                              p_sdp->username, &p_sdp->session_id,
  1064.                              &p_sdp->session_version, &p_sdp->orig_ip_version,
  1065.                              p_sdp->orig_host) != 5)
  1066.                  || ((p_sdp->orig_ip_version != 4)
  1067.                   && (p_sdp->orig_ip_version != 6)))
  1068.                 {
  1069.                     msg_Dbg (p_obj, "SDP origin not supported: %s", data);
  1070.                     /* Or maybe out-of-range, but this looks suspicious */
  1071.                     return NULL;
  1072.                 }
  1073.                 EnsureUTF8 (p_sdp->orig_host);
  1074.                 break;
  1075.             }
  1076.             case 'S':
  1077.             {
  1078.                 expect = 'I';
  1079.                 if ((cat != 's') || !*data)
  1080.                 {
  1081.                     /* MUST be present AND non-empty */
  1082.                     msg_Dbg (p_obj, "missing SDP session name");
  1083.                     goto error;
  1084.                 }
  1085.                 assert (p_sdp->psz_sessionname == NULL); // no memleak here
  1086.                 p_sdp->psz_sessionname = strdup (data);
  1087.                 if (p_sdp->psz_sessionname == NULL)
  1088.                     goto error;
  1089.                 EnsureUTF8 (p_sdp->psz_sessionname);
  1090.                 break;
  1091.             }
  1092.             case 'I':
  1093.                 expect = 'U';
  1094.                 if (cat == 'i')
  1095.                     break;
  1096.             case 'U':
  1097.                 expect = 'E';
  1098.                 if (cat == 'u')
  1099.                     break;
  1100.             case 'E':
  1101.                 expect = 'E';
  1102.                 if (cat == 'e')
  1103.                     break;
  1104.             case 'P':
  1105.                 expect = 'P';
  1106.                 if (cat == 'p')
  1107.                     break;
  1108.             case 'C':
  1109.                 expect = 'B';
  1110.                 if (cat == 'c')
  1111.                 {
  1112.                     if (ParseSDPConnection (data, &glob_addr, &glob_len,
  1113.                                             &glob_count))
  1114.                     {
  1115.                         msg_Dbg (p_obj, "SDP connection infos not supported: "
  1116.                                  "%s", data);
  1117.                         goto error;
  1118.                     }
  1119.                     break;
  1120.                 }
  1121.             case 'B':
  1122.                 assert (expect == 'B');
  1123.                 if (cat == 'b')
  1124.                     break;
  1125.             case 'T':
  1126.                 expect = 'R';
  1127.                 if (cat != 't')
  1128.                 {
  1129.                     msg_Dbg (p_obj, "missing SDP time description");
  1130.                     goto error;
  1131.                 }
  1132.                 break;
  1133.             case 'R':
  1134.                 if ((cat == 't') || (cat == 'r'))
  1135.                     break;
  1136.             case 'Z':
  1137.                 expect = 'K';
  1138.                 if (cat == 'z')
  1139.                     break;
  1140.             case 'K':
  1141.                 expect = 'A';
  1142.                 if (cat == 'k')
  1143.                     break;
  1144.             case 'A':
  1145.                 //expect = 'A';
  1146.                 if (cat == 'a')
  1147.                 {
  1148.                     attribute_t *p_attr = MakeAttribute (data);
  1149.                     TAB_APPEND( p_sdp->i_attributes, p_sdp->pp_attributes, p_attr );
  1150.                     break;
  1151.                 }
  1152.             /* Media description */
  1153.             case 'm':
  1154.             media:
  1155.             {
  1156.                 expect = 'i';
  1157.                 if (cat != 'm')
  1158.                 {
  1159.                     msg_Dbg (p_obj, "missing SDP media description");
  1160.                     goto error;
  1161.                 }
  1162.                 struct sdp_media_t *m;
  1163.                 m = realloc (p_sdp->mediav, (p_sdp->mediac + 1) * sizeof (*m));
  1164.                 if (m == NULL)
  1165.                     goto error;
  1166.                 p_sdp->mediav = m;
  1167.                 m += p_sdp->mediac;
  1168.                 p_sdp->mediac++;
  1169.                 memset (m, 0, sizeof (*m));
  1170.                 memcpy (&m->addr, &glob_addr, m->addrlen = glob_len);
  1171.                 m->n_addr = glob_count;
  1172.                 /* TODO: remember media type (if we need multiple medias) */
  1173.                 data = strchr (data, ' ');
  1174.                 if (data == NULL)
  1175.                 {
  1176.                     msg_Dbg (p_obj, "missing SDP media port");
  1177.                     goto error;
  1178.                 }
  1179.                 port = atoi (++data);
  1180.                 if (port <= 0 || port >= 65536)
  1181.                 {
  1182.                     msg_Dbg (p_obj, "invalid transport port %d", port);
  1183.                     goto error;
  1184.                 }
  1185.                 net_SetPort ((struct sockaddr *)&m->addr, htons (port));
  1186.                 data = strchr (data, ' ');
  1187.                 if (data == NULL)
  1188.                 {
  1189.                     msg_Dbg (p_obj, "missing SDP media format");
  1190.                     goto error;
  1191.                 }
  1192.                 m->fmt = strdup (++data);
  1193.                 if (m->fmt == NULL)
  1194.                     goto error;
  1195.                 break;
  1196.             }
  1197.             case 'i':
  1198.                 expect = 'c';
  1199.                 if (cat == 'i')
  1200.                     break;
  1201.             case 'c':
  1202.                 expect = 'b';
  1203.                 if (cat == 'c')
  1204.                 {
  1205.                     struct sdp_media_t *m = p_sdp->mediav + p_sdp->mediac - 1;
  1206.                     if (ParseSDPConnection (data, &m->addr, &m->addrlen,
  1207.                                             &m->n_addr))
  1208.                     {
  1209.                         msg_Dbg (p_obj, "SDP connection infos not supported: "
  1210.                                  "%s", data);
  1211.                         goto error;
  1212.                     }
  1213.                     net_SetPort ((struct sockaddr *)&m->addr, htons (port));
  1214.                     break;
  1215.                 }
  1216.             case 'b':
  1217.                 expect = 'b';
  1218.                 if (cat == 'b')
  1219.                     break;
  1220.             case 'k':
  1221.                 expect = 'a';
  1222.                 if (cat == 'k')
  1223.                     break;
  1224.             case 'a':
  1225.                 assert (expect == 'a');
  1226.                 if (cat == 'a')
  1227.                 {
  1228.                     attribute_t *p_attr = MakeAttribute (data);
  1229.                     if (p_attr == NULL)
  1230.                         goto error;
  1231.                     TAB_APPEND (p_sdp->mediav[p_sdp->mediac - 1].i_attributes,
  1232.                                 p_sdp->mediav[p_sdp->mediac - 1].pp_attributes, p_attr);
  1233.                     break;
  1234.                 }
  1235.                 if (cat == 'm')
  1236.                     goto media;
  1237.                 if (cat != 'm')
  1238.                 {
  1239.                     msg_Dbg (p_obj, "unexpected SDP line: 0x%02x", (int)cat);
  1240.                     goto error;
  1241.                 }
  1242.                 break;
  1243.             default:
  1244.                 msg_Err (p_obj, "*** BUG in SDP parser! ***");
  1245.                 goto error;
  1246.         }
  1247.     }
  1248.     return p_sdp;
  1249. error:
  1250.     FreeSDP (p_sdp);
  1251.     return NULL;
  1252. }
  1253. static int InitSocket( services_discovery_t *p_sd, const char *psz_address,
  1254.                        int i_port )
  1255. {
  1256.     int i_fd = net_ListenUDP1 ((vlc_object_t *)p_sd, psz_address, i_port);
  1257.     if (i_fd == -1)
  1258.         return VLC_EGENERIC;
  1259.     shutdown( i_fd, SHUT_WR );
  1260.     INSERT_ELEM (p_sd->p_sys->pi_fd, p_sd->p_sys->i_fd,
  1261.                  p_sd->p_sys->i_fd, i_fd);
  1262.     return VLC_SUCCESS;
  1263. }
  1264. static int Decompress( const unsigned char *psz_src, unsigned char **_dst, int i_len )
  1265. {
  1266. #ifdef HAVE_ZLIB_H
  1267.     int i_result, i_dstsize, n = 0;
  1268.     unsigned char *psz_dst = NULL;
  1269.     z_stream d_stream;
  1270.     memset (&d_stream, 0, sizeof (d_stream));
  1271.     i_result = inflateInit(&d_stream);
  1272.     if( i_result != Z_OK )
  1273.         return( -1 );
  1274.     d_stream.next_in = (Bytef *)psz_src;
  1275.     d_stream.avail_in = i_len;
  1276.     do
  1277.     {
  1278.         n++;
  1279.         psz_dst = (unsigned char *)realloc( psz_dst, n * 1000 );
  1280.         d_stream.next_out = (Bytef *)&psz_dst[(n - 1) * 1000];
  1281.         d_stream.avail_out = 1000;
  1282.         i_result = inflate(&d_stream, Z_NO_FLUSH);
  1283.         if( ( i_result != Z_OK ) && ( i_result != Z_STREAM_END ) )
  1284.         {
  1285.             inflateEnd( &d_stream );
  1286.             free( psz_dst );
  1287.             return( -1 );
  1288.         }
  1289.     }
  1290.     while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
  1291.            ( i_result != Z_STREAM_END ) );
  1292.     i_dstsize = d_stream.total_out;
  1293.     inflateEnd( &d_stream );
  1294.     *_dst = (unsigned char *)realloc( psz_dst, i_dstsize );
  1295.     return i_dstsize;
  1296. #else
  1297.     (void)psz_src;
  1298.     (void)_dst;
  1299.     (void)i_len;
  1300.     return -1;
  1301. #endif
  1302. }
  1303. static void FreeSDP( sdp_t *p_sdp )
  1304. {
  1305.     free( p_sdp->psz_sessionname );
  1306.     free( p_sdp->psz_uri );
  1307.     for (unsigned j = 0; j < p_sdp->mediac; j++)
  1308.     {
  1309.         free (p_sdp->mediav[j].fmt);
  1310.         for (int i = 0; i < p_sdp->mediav[j].i_attributes; i++)
  1311.             FreeAttribute (p_sdp->mediav[j].pp_attributes[i]);
  1312.         free (p_sdp->mediav[j].pp_attributes);
  1313.     }
  1314.     free (p_sdp->mediav);
  1315.     for (int i = 0; i < p_sdp->i_attributes; i++)
  1316.         FreeAttribute (p_sdp->pp_attributes[i]);
  1317.     free (p_sdp->pp_attributes);
  1318.     free (p_sdp);
  1319. }
  1320. static int RemoveAnnounce( services_discovery_t *p_sd,
  1321.                            sap_announce_t *p_announce )
  1322. {
  1323.     int i;
  1324.     if( p_announce->p_sdp )
  1325.     {
  1326.         FreeSDP( p_announce->p_sdp );
  1327.         p_announce->p_sdp = NULL;
  1328.     }
  1329.     if( p_announce->p_item )
  1330.     {
  1331.         services_discovery_RemoveItem( p_sd, p_announce->p_item );
  1332.         vlc_gc_decref( p_announce->p_item );
  1333.         p_announce->p_item = NULL;
  1334.     }
  1335.     for( i = 0; i< p_sd->p_sys->i_announces; i++)
  1336.     {
  1337.         if( p_sd->p_sys->pp_announces[i] == p_announce )
  1338.         {
  1339.             REMOVE_ELEM( p_sd->p_sys->pp_announces, p_sd->p_sys->i_announces,
  1340.                          i);
  1341.             break;
  1342.         }
  1343.     }
  1344.     free( p_announce );
  1345.     return VLC_SUCCESS;
  1346. }
  1347. static bool IsSameSession( sdp_t *p_sdp1, sdp_t *p_sdp2 )
  1348. {
  1349.     /* A session is identified by
  1350.      * - username,
  1351.      * - session_id,
  1352.      * - network type (which is always IN),
  1353.      * - address type (currently, this means IP version),
  1354.      * - and hostname.
  1355.      */
  1356.     if (strcmp (p_sdp1->username, p_sdp2->username)
  1357.      || (p_sdp1->session_id != p_sdp2->session_id)
  1358.      || (p_sdp1->orig_ip_version != p_sdp2->orig_ip_version)
  1359.      || strcmp (p_sdp1->orig_host, p_sdp2->orig_host))
  1360.         return false;
  1361.     return true;
  1362. }
  1363. static inline attribute_t *MakeAttribute (const char *str)
  1364. {
  1365.     attribute_t *a = malloc (sizeof (*a) + strlen (str) + 1);
  1366.     if (a == NULL)
  1367.         return NULL;
  1368.     strcpy (a->name, str);
  1369.     EnsureUTF8 (a->name);
  1370.     char *value = strchr (a->name, ':');
  1371.     if (value != NULL)
  1372.     {
  1373.         *value++ = '';
  1374.         a->value = value;
  1375.     }
  1376.     else
  1377.         a->value = "";
  1378.     return a;
  1379. }
  1380. static const char *GetAttribute (attribute_t **tab, unsigned n,
  1381.                                  const char *name)
  1382. {
  1383.     for (unsigned i = 0; i < n; i++)
  1384.         if (strcasecmp (tab[i]->name, name) == 0)
  1385.             return tab[i]->value;
  1386.     return NULL;
  1387. }
  1388. static inline void FreeAttribute (attribute_t *a)
  1389. {
  1390.     free (a);
  1391. }