📄 sap.c
字号:
case 0: /* PCMU/8000 */ case 8: /* PCMA/8000 */ case 10: /* L16/44100/2 */ case 11: /* L16/44100 */ case 14: /* MPA/90000 */ case 32: /* MPV/90000 */ case 33: /* MP2/90000 */ break; default: 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; 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 5000static void Run( services_discovery_t *p_sd ){ char *psz_addr; int i; int timeout = -1; /* 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, '%') = '\0'; 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; } /* read SAP packets */ while( vlc_object_alive( p_sd ) ) { unsigned n = p_sd->p_sys->i_fd; struct pollfd ufd[n+1]; 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; } /* Make sure we track vlc_object_signal() */ ufd[n].fd = vlc_object_waitpipe( p_sd ); ufd[n].events = POLLIN; ufd[n].revents = 0; if (poll (ufd, n+1, timeout) > 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] = '\0'; 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. */ }}/********************************************************************** * 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 yield 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 ); vlc_mutex_lock( &p_parent_input->lock ); p_parent_input->i_type = ITEM_TYPE_NET; vlc_mutex_unlock( &p_parent_input->lock ); 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] == '\0'); 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] = '\0'; 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 \0 */ assert( psz_sdp[len] == '\0'); /* Skip payload type */ /* SAPv1 has implicit "application/sdp" payload type: first line is v=0 */ if (strncmp (psz_sdp, "v=0", 3)) { size_t clen = strlen (psz_sdp) + 1; if (strcmp (psz_sdp, "application/sdp")) { msg_Dbg (p_sd, "unsupported content type: %s", psz_sdp); return VLC_EGENERIC; } // skips content type if (len <= clen) return VLC_EGENERIC; len -= clen; psz_sdp += clen; } /* Parse SDP info */ p_sdp = ParseSDP( VLC_OBJECT(p_sd), psz_sdp ); if( p_sdp == NULL ) return VLC_EGENERIC; p_sdp->psz_sdp = psz_sdp; /* Decide whether we should add a playlist item for this SDP */ /* Parse connection information (c= & m= ) */ if( ParseConnection( VLC_OBJECT(p_sd), p_sdp ) ) p_sdp->psz_uri = NULL; /* Multi-media or no-parse -> pass to LIVE.COM */ if( ( p_sdp->i_media_type != 14 && p_sdp->i_media_type != 32 && p_sdp->i_media_type != 33) || p_sd->p_sys->b_parse == false ) { free( p_sdp->psz_uri ); if (asprintf( &p_sdp->psz_uri, "sdp://%s", p_sdp->psz_sdp ) == -1) p_sdp->psz_uri = NULL; } if( p_sdp->psz_uri == NULL ) { FreeSDP( p_sdp ); return VLC_EGENERIC;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -