sap.c
资源名称:vlc-1.0.5.zip [点击查看]
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:48k
源码类别:
midi
开发平台:
Unix_Linux
- /*****************************************************************************
- * sap.c : SAP interface module
- *****************************************************************************
- * Copyright (C) 2004-2005 the VideoLAN team
- * Copyright © 2007 Rémi Denis-Courmont
- * $Id: 803ffb7224069f7f08ed2e187c57939ef02e2cdb $
- *
- * Authors: Clément Stenac <zorglub@videolan.org>
- * Rémi Denis-Courmont
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
- /*****************************************************************************
- * Includes
- *****************************************************************************/
- #ifdef HAVE_CONFIG_H
- # include "config.h"
- #endif
- #include <vlc_common.h>
- #include <vlc_plugin.h>
- #include <assert.h>
- #include <vlc_demux.h>
- #include <vlc_services_discovery.h>
- #include <vlc_network.h>
- #include <vlc_charset.h>
- #include <ctype.h>
- #include <errno.h>
- #ifdef HAVE_UNISTD_H
- # include <unistd.h>
- #endif
- #ifdef HAVE_SYS_TIME_H
- # include <sys/time.h>
- #endif
- #ifdef HAVE_POLL
- # include <poll.h>
- #endif
- #ifdef HAVE_ZLIB_H
- # include <zlib.h>
- #endif
- #ifndef WIN32
- # include <net/if.h>
- #endif
- /************************************************************************
- * Macros and definitions
- ************************************************************************/
- #define MAX_LINE_LENGTH 256
- /* SAP is always on that port */
- #define SAP_PORT 9875
- /* Global-scope SAP address */
- #define SAP_V4_GLOBAL_ADDRESS "224.2.127.254"
- /* Organization-local SAP address */
- #define SAP_V4_ORG_ADDRESS "239.195.255.255"
- /* Local (smallest non-link-local scope) SAP address */
- #define SAP_V4_LOCAL_ADDRESS "239.255.255.255"
- /* Link-local SAP address */
- #define SAP_V4_LINK_ADDRESS "224.0.0.255"
- #define ADD_SESSION 1
- /*****************************************************************************
- * Module descriptor
- *****************************************************************************/
- #define SAP_ADDR_TEXT N_( "SAP multicast address" )
- #define SAP_ADDR_LONGTEXT N_( "The SAP module normally chooses itself the "
- "right addresses to listen to. However, you "
- "can specify a specific address." )
- #define SAP_IPV4_TEXT N_( "IPv4 SAP" )
- #define SAP_IPV4_LONGTEXT N_(
- "Listen to IPv4 announcements on the standard addresses." )
- #define SAP_IPV6_TEXT N_( "IPv6 SAP" )
- #define SAP_IPV6_LONGTEXT N_(
- "Listen to IPv6 announcements on the standard addresses." )
- #define SAP_SCOPE_TEXT N_( "IPv6 SAP scope" )
- #define SAP_SCOPE_LONGTEXT N_(
- "Scope for IPv6 announcements (default is 8)." )
- #define SAP_TIMEOUT_TEXT N_( "SAP timeout (seconds)" )
- #define SAP_TIMEOUT_LONGTEXT N_(
- "Delay after which SAP items get deleted if no new announcement "
- "is received." )
- #define SAP_PARSE_TEXT N_( "Try to parse the announce" )
- #define SAP_PARSE_LONGTEXT N_(
- "This enables actual parsing of the announces by the SAP module. "
- "Otherwise, all announcements are parsed by the "live555" "
- "(RTP/RTSP) module." )
- #define SAP_STRICT_TEXT N_( "SAP Strict mode" )
- #define SAP_STRICT_LONGTEXT N_(
- "When this is set, the SAP parser will discard some non-compliant "
- "announcements." )
- #define SAP_CACHE_TEXT N_("Use SAP cache")
- #define SAP_CACHE_LONGTEXT N_(
- "This enables a SAP caching mechanism. "
- "This will result in lower SAP startup time, but you could end up "
- "with items corresponding to legacy streams." )
- /* Callbacks */
- static int Open ( vlc_object_t * );
- static void Close( vlc_object_t * );
- static int OpenDemux ( vlc_object_t * );
- static void CloseDemux ( vlc_object_t * );
- vlc_module_begin ()
- set_shortname( N_("SAP"))
- set_description( N_("SAP Announcements") )
- set_category( CAT_PLAYLIST )
- set_subcategory( SUBCAT_PLAYLIST_SD )
- add_string( "sap-addr", NULL, NULL,
- SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, true )
- add_bool( "sap-ipv4", 1 , NULL,
- SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, true )
- add_bool( "sap-ipv6", 1 , NULL,
- SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, true )
- add_integer( "sap-timeout", 1800, NULL,
- SAP_TIMEOUT_TEXT, SAP_TIMEOUT_LONGTEXT, true )
- add_bool( "sap-parse", 1 , NULL,
- SAP_PARSE_TEXT,SAP_PARSE_LONGTEXT, true )
- add_bool( "sap-strict", 0 , NULL,
- SAP_STRICT_TEXT,SAP_STRICT_LONGTEXT, true )
- #if 0
- add_bool( "sap-cache", 0 , NULL,
- SAP_CACHE_TEXT,SAP_CACHE_LONGTEXT, true )
- #endif
- add_obsolete_bool( "sap-timeshift" ) /* Redumdant since 1.0.0 */
- set_capability( "services_discovery", 0 )
- set_callbacks( Open, Close )
- add_submodule ()
- set_description( N_("SDP Descriptions parser") )
- add_shortcut( "sdp" )
- set_capability( "demux", 51 )
- set_callbacks( OpenDemux, CloseDemux )
- vlc_module_end ()
- /*****************************************************************************
- * Local structures
- *****************************************************************************/
- typedef struct sdp_t sdp_t;
- typedef struct attribute_t attribute_t;
- typedef struct sap_announce_t sap_announce_t;
- struct sdp_media_t
- {
- struct sdp_t *parent;
- char *fmt;
- struct sockaddr_storage addr;
- socklen_t addrlen;
- unsigned n_addr;
- int i_attributes;
- attribute_t **pp_attributes;
- };
- /* The structure that contains sdp information */
- struct sdp_t
- {
- const char *psz_sdp;
- /* o field */
- char username[64];
- uint64_t session_id;
- uint64_t session_version;
- unsigned orig_ip_version;
- char orig_host[1024];
- /* s= field */
- char *psz_sessionname;
- /* old cruft */
- /* "computed" URI */
- char *psz_uri;
- int i_media_type;
- unsigned rtcp_port;
- /* a= global attributes */
- int i_attributes;
- attribute_t **pp_attributes;
- /* medias (well, we only support one atm) */
- unsigned mediac;
- struct sdp_media_t *mediav;
- };
- struct attribute_t
- {
- const char *value;
- char name[];
- };
- struct sap_announce_t
- {
- mtime_t i_last;
- mtime_t i_period;
- uint8_t i_period_trust;
- uint16_t i_hash;
- uint32_t i_source[4];
- /* SAP annnounces must only contain one SDP */
- sdp_t *p_sdp;
- input_item_t * p_item;
- };
- struct services_discovery_sys_t
- {
- vlc_thread_t thread;
- /* Socket descriptors */
- int i_fd;
- int *pi_fd;
- /* Table of announces */
- int i_announces;
- struct sap_announce_t **pp_announces;
- /* Modes */
- bool b_strict;
- bool b_parse;
- int i_timeout;
- };
- struct demux_sys_t
- {
- sdp_t *p_sdp;
- };
- /*****************************************************************************
- * Local prototypes
- *****************************************************************************/
- /* Main functions */
- static int Demux( demux_t *p_demux );
- static int Control( demux_t *, int, va_list );
- static void *Run ( void *p_sd );
- /* Main parsing functions */
- static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp );
- static int ParseSAP( services_discovery_t *p_sd, const uint8_t *p_buffer, size_t i_read );
- static sdp_t *ParseSDP (vlc_object_t *p_sd, const char *psz_sdp);
- static sap_announce_t *CreateAnnounce( services_discovery_t *, uint16_t, sdp_t * );
- static int RemoveAnnounce( services_discovery_t *p_sd, sap_announce_t *p_announce );
- /* Helper functions */
- 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 bool IsSameSession( sdp_t *p_sdp1, sdp_t *p_sdp2 );
- static int InitSocket( services_discovery_t *p_sd, const char *psz_address, int i_port );
- static int Decompress( const unsigned char *psz_src, unsigned char **_dst, int i_len );
- static void FreeSDP( sdp_t *p_sdp );
- static inline int min_int( int a, int b )
- {
- return a > b ? b : a;
- }
- static bool IsWellKnownPayload (int type)
- {
- switch (type)
- { /* Should be in sync with modules/demux/rtp.c */
- case 0: /* PCMU/8000 */
- case 3:
- case 8: /* PCMA/8000 */
- case 10: /* L16/44100/2 */
- case 11: /* L16/44100 */
- case 12:
- case 14: /* MPA/90000 */
- case 32: /* MPV/90000 */
- case 33: /* MP2/90000 */
- return true;
- }
- return false;
- }
- /*****************************************************************************
- * Open: initialize and create stuff
- *****************************************************************************/
- static int Open( vlc_object_t *p_this )
- {
- services_discovery_t *p_sd = ( services_discovery_t* )p_this;
- services_discovery_sys_t *p_sys = (services_discovery_sys_t *)
- malloc( sizeof( services_discovery_sys_t ) );
- if( !p_sys )
- return VLC_ENOMEM;
- p_sys->i_timeout = var_CreateGetInteger( p_sd, "sap-timeout" );
- p_sd->p_sys = p_sys;
- p_sys->pi_fd = NULL;
- p_sys->i_fd = 0;
- p_sys->b_strict = var_CreateGetInteger( p_sd, "sap-strict");
- p_sys->b_parse = var_CreateGetInteger( p_sd, "sap-parse" );
- #if 0
- if( var_CreateGetInteger( p_sd, "sap-cache" ) )
- {
- CacheLoad( p_sd );
- }
- #endif
- p_sys->i_announces = 0;
- p_sys->pp_announces = NULL;
- /* TODO: create sockets here, and fix racy sockets table */
- if (vlc_clone (&p_sys->thread, Run, p_sd, VLC_THREAD_PRIORITY_LOW))
- {
- free (p_sys);
- return VLC_EGENERIC;
- }
- return VLC_SUCCESS;
- }
- /*****************************************************************************
- * OpenDemux: initialize and create stuff
- *****************************************************************************/
- static int OpenDemux( vlc_object_t *p_this )
- {
- demux_t *p_demux = (demux_t *)p_this;
- const uint8_t *p_peek;
- char *psz_sdp = NULL;
- sdp_t *p_sdp = NULL;
- int errval = VLC_EGENERIC;
- size_t i_len;
- if( !var_CreateGetInteger( p_demux, "sap-parse" ) )
- {
- /* We want livedotcom module to parse this SDP file */
- return VLC_EGENERIC;
- }
- assert( p_demux->s ); /* this is NOT an access_demux */
- /* Probe for SDP */
- if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 )
- return VLC_EGENERIC;
- if( memcmp( p_peek, "v=0rno=", 7 ) && memcmp( p_peek, "v=0no=", 6 ) )
- return VLC_EGENERIC;
- /* Gather the complete sdp file */
- for( i_len = 0, psz_sdp = NULL; i_len < 65536; )
- {
- const int i_read_max = 1024;
- char *psz_sdp_new = realloc( psz_sdp, i_len + i_read_max );
- size_t i_read;
- if( psz_sdp_new == NULL )
- {
- errval = VLC_ENOMEM;
- goto error;
- }
- psz_sdp = psz_sdp_new;
- i_read = stream_Read( p_demux->s, &psz_sdp[i_len], i_read_max );
- if( (int)i_read < 0 )
- {
- msg_Err( p_demux, "cannot read SDP" );
- goto error;
- }
- i_len += i_read;
- psz_sdp[i_len] = ' ';
- if( (int)i_read < i_read_max )
- break; // EOF
- }
- p_sdp = ParseSDP( VLC_OBJECT(p_demux), psz_sdp );
- if( !p_sdp )
- {
- msg_Warn( p_demux, "invalid SDP");
- goto error;
- }
- if( ParseConnection( VLC_OBJECT( p_demux ), p_sdp ) )
- {
- p_sdp->psz_uri = NULL;
- }
- if (!IsWellKnownPayload (p_sdp->i_media_type))
- goto error;
- if( p_sdp->psz_uri == NULL ) goto error;
- p_demux->p_sys = (demux_sys_t *)malloc( sizeof(demux_sys_t) );
- p_demux->p_sys->p_sdp = p_sdp;
- p_demux->pf_control = Control;
- p_demux->pf_demux = Demux;
- FREENULL( psz_sdp );
- return VLC_SUCCESS;
- error:
- FREENULL( psz_sdp );
- if( p_sdp ) FreeSDP( p_sdp ); p_sdp = NULL;
- stream_Seek( p_demux->s, 0 );
- return errval;
- }
- /*****************************************************************************
- * Close:
- *****************************************************************************/
- static void Close( vlc_object_t *p_this )
- {
- services_discovery_t *p_sd = ( services_discovery_t* )p_this;
- services_discovery_sys_t *p_sys = p_sd->p_sys;
- int i;
- vlc_cancel (p_sys->thread);
- vlc_join (p_sys->thread, NULL);
- for( i = p_sys->i_fd-1 ; i >= 0 ; i-- )
- {
- net_Close( p_sys->pi_fd[i] );
- }
- FREENULL( p_sys->pi_fd );
- #if 0
- if( config_GetInt( p_sd, "sap-cache" ) )
- {
- CacheSave( p_sd );
- }
- #endif
- for( i = p_sys->i_announces - 1; i>= 0; i-- )
- {
- RemoveAnnounce( p_sd, p_sys->pp_announces[i] );
- }
- FREENULL( p_sys->pp_announces );
- free( p_sys );
- }
- /*****************************************************************************
- * CloseDemux: Close the demuxer
- *****************************************************************************/
- static void CloseDemux( vlc_object_t *p_this )
- {
- demux_t *p_demux = (demux_t *)p_this;
- if( p_demux->p_sys )
- {
- if( p_demux->p_sys->p_sdp ) { FreeSDP( p_demux->p_sys->p_sdp ); p_demux->p_sys->p_sdp = NULL; }
- free( p_demux->p_sys );
- }
- }
- /*****************************************************************************
- * Run: main SAP thread
- *****************************************************************************
- * Listens to SAP packets, and sends them to packet_handle
- *****************************************************************************/
- #define MAX_SAP_BUFFER 5000
- static void *Run( void *data )
- {
- services_discovery_t *p_sd = data;
- char *psz_addr;
- int i;
- int timeout = -1;
- int canc = vlc_savecancel ();
- /* Braindead Winsock DNS resolver will get stuck over 2 seconds per failed
- * DNS queries, even if the DNS server returns an error with milliseconds.
- * You don't want to know why the bug (as of XP SP2) wasn't fixed since
- * Winsock 1.1 from Windows 95, if not Windows 3.1.
- * Anyway, to avoid a 30 seconds delay for failed IPv6 socket creation,
- * we have to open sockets in Run() rather than Open(). */
- if( var_CreateGetInteger( p_sd, "sap-ipv4" ) )
- {
- InitSocket( p_sd, SAP_V4_GLOBAL_ADDRESS, SAP_PORT );
- InitSocket( p_sd, SAP_V4_ORG_ADDRESS, SAP_PORT );
- InitSocket( p_sd, SAP_V4_LOCAL_ADDRESS, SAP_PORT );
- InitSocket( p_sd, SAP_V4_LINK_ADDRESS, SAP_PORT );
- }
- if( var_CreateGetInteger( p_sd, "sap-ipv6" ) )
- {
- char psz_address[NI_MAXNUMERICHOST] = "ff02::2:7ffe%";
- #ifndef WIN32
- 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);
- }
- #else
- /* this is the Winsock2 equivalant of SIOCGIFCONF on BSD stacks,
- which if_nameindex uses internally anyway */
- // first create a dummy socket to pin down the protocol family
- SOCKET s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
- if( s != INVALID_SOCKET )
- {
- INTERFACE_INFO ifaces[10]; // Assume there will be no more than 10 IP interfaces
- size_t len = sizeof(ifaces);
- if( SOCKET_ERROR != WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0, &ifaces, len, &len, NULL, NULL) )
- {
- unsigned ifcount = len/sizeof(INTERFACE_INFO);
- char *ptr = strchr (psz_address, '%') + 1;
- for(unsigned i = 1; i<=ifcount; ++i )
- {
- // append link-local zone identifier
- sprintf(ptr, "%d", i);
- }
- }
- closesocket(s);
- }
- #endif
- *strchr (psz_address, '%') = ' ';
- static const char ipv6_scopes[] = "1456789ABCDE";
- for (const char *c_scope = ipv6_scopes; *c_scope; c_scope++)
- {
- psz_address[3] = *c_scope;
- InitSocket( p_sd, psz_address, SAP_PORT );
- }
- }
- psz_addr = var_CreateGetString( p_sd, "sap-addr" );
- if( psz_addr && *psz_addr )
- InitSocket( p_sd, psz_addr, SAP_PORT );
- free( psz_addr );
- if( p_sd->p_sys->i_fd == 0 )
- {
- msg_Err( p_sd, "unable to listen on any address" );
- return NULL;
- }
- /* read SAP packets */
- for (;;)
- {
- vlc_restorecancel (canc);
- unsigned n = p_sd->p_sys->i_fd;
- struct pollfd ufd[n];
- for (unsigned i = 0; i < n; i++)
- {
- ufd[i].fd = p_sd->p_sys->pi_fd[i];
- ufd[i].events = POLLIN;
- ufd[i].revents = 0;
- }
- int val = poll (ufd, n, timeout);
- canc = vlc_savecancel ();
- if (val > 0)
- {
- for (unsigned i = 0; i < n; i++)
- {
- if (ufd[i].revents)
- {
- uint8_t p_buffer[MAX_SAP_BUFFER+1];
- ssize_t i_read;
- i_read = net_Read (p_sd, ufd[i].fd, NULL, p_buffer,
- MAX_SAP_BUFFER, false);
- if (i_read < 0)
- msg_Warn (p_sd, "receive error: %m");
- if (i_read > 6)
- {
- /* Parse the packet */
- p_buffer[i_read] = ' ';
- ParseSAP (p_sd, p_buffer, i_read);
- }
- }
- }
- }
- mtime_t now = mdate();
- /* A 1 hour timeout correspong to the RFC Implicit timeout.
- * This timeout is tuned in the following loop. */
- timeout = 1000 * 60 * 60;
- /* Check for items that need deletion */
- for( i = 0; i < p_sd->p_sys->i_announces; i++ )
- {
- mtime_t i_timeout = ( mtime_t ) 1000000 * p_sd->p_sys->i_timeout;
- sap_announce_t * p_announce = p_sd->p_sys->pp_announces[i];
- mtime_t i_last_period = now - p_announce->i_last;
- /* Remove the annoucement, if the last announcement was 1 hour ago
- * or if the last packet emitted was 3 times the average time
- * between two packets */
- if( ( p_announce->i_period_trust > 5 && i_last_period > 3 * p_announce->i_period ) ||
- i_last_period > i_timeout )
- {
- RemoveAnnounce( p_sd, p_announce );
- }
- else
- {
- /* Compute next timeout */
- if( p_announce->i_period_trust > 5 )
- timeout = min_int((3 * p_announce->i_period - i_last_period) / 1000, timeout);
- timeout = min_int((i_timeout - i_last_period)/1000, timeout);
- }
- }
- if( !p_sd->p_sys->i_announces )
- timeout = -1; /* We can safely poll indefinitly. */
- else if( timeout < 200 )
- timeout = 200; /* Don't wakeup too fast. */
- }
- assert (0);
- }
- /**********************************************************************
- * Demux: reads and demuxes data packets
- * Return -1 if error, 0 if EOF, 1 else
- **********************************************************************/
- static int Demux( demux_t *p_demux )
- {
- sdp_t *p_sdp = p_demux->p_sys->p_sdp;
- input_thread_t *p_input;
- input_item_t *p_parent_input;
- p_input = (input_thread_t *)vlc_object_find( p_demux, VLC_OBJECT_INPUT,
- FIND_PARENT );
- assert( p_input );
- if( !p_input )
- {
- msg_Err( p_demux, "parent input could not be found" );
- return VLC_EGENERIC;
- }
- /* This item hasn't been held by input_GetItem
- * don't release it */
- p_parent_input = input_GetItem( p_input );
- input_item_SetURI( p_parent_input, p_sdp->psz_uri );
- input_item_SetName( p_parent_input, p_sdp->psz_sessionname );
- if( p_sdp->rtcp_port )
- {
- char *rtcp;
- if( asprintf( &rtcp, ":rtcp-port=%u", p_sdp->rtcp_port ) != -1 )
- {
- input_item_AddOption( p_parent_input, rtcp, VLC_INPUT_OPTION_TRUSTED );
- free( rtcp );
- }
- }
- vlc_mutex_lock( &p_parent_input->lock );
- p_parent_input->i_type = ITEM_TYPE_NET;
- vlc_mutex_unlock( &p_parent_input->lock );
- vlc_object_release( p_input );
- return VLC_SUCCESS;
- }
- static int Control( demux_t *p_demux, int i_query, va_list args )
- {
- VLC_UNUSED(p_demux); VLC_UNUSED(i_query); VLC_UNUSED(args);
- return VLC_EGENERIC;
- }
- /**************************************************************
- * Local functions
- **************************************************************/
- /* i_read is at least > 6 */
- static int ParseSAP( services_discovery_t *p_sd, const uint8_t *buf,
- size_t len )
- {
- int i;
- const char *psz_sdp;
- const uint8_t *end = buf + len;
- sdp_t *p_sdp;
- assert (buf[len] == ' ');
- if (len < 4)
- return VLC_EGENERIC;
- uint8_t flags = buf[0];
- /* First, check the sap announce is correct */
- if ((flags >> 5) != 1)
- return VLC_EGENERIC;
- bool b_ipv6 = (flags & 0x10) != 0;
- bool b_need_delete = (flags & 0x04) != 0;
- if (flags & 0x02)
- {
- msg_Dbg( p_sd, "encrypted packet, unsupported" );
- return VLC_EGENERIC;
- }
- bool b_compressed = (flags & 0x01) != 0;
- uint16_t i_hash = U16_AT (buf + 2);
- if( p_sd->p_sys->b_strict && i_hash == 0 )
- {
- msg_Dbg( p_sd, "strict mode, discarding announce with null id hash");
- return VLC_EGENERIC;
- }
- // Skips source address and auth data
- buf += 4 + (b_ipv6 ? 16 : 4) + buf[1];
- if (buf > end)
- return VLC_EGENERIC;
- uint8_t *decomp = NULL;
- if( b_compressed )
- {
- int newsize = Decompress (buf, &decomp, end - buf);
- if (newsize < 0)
- {
- msg_Dbg( p_sd, "decompression of SAP packet failed" );
- return VLC_EGENERIC;
- }
- decomp = realloc (decomp, newsize + 1);
- decomp[newsize] = ' ';
- psz_sdp = (const char *)decomp;
- len = newsize;
- }
- else
- {
- psz_sdp = (const char *)buf;
- len = end - buf;
- }
- /* len is a strlen here here. both buf and decomp are len+1 where the 1 should be a