📄 sap.c
字号:
} for( i = 0 ; i< p_sd->p_sys->i_announces ; i++ ) { sap_announce_t * p_announce = p_sd->p_sys->pp_announces[i]; /* FIXME: slow */ /* FIXME: we create a new announce each time the sdp changes */ if( IsSameSession( p_announce->p_sdp, p_sdp ) ) { /* We don't support delete announcement as they can easily * Be used to highjack an announcement by a third party. * Intead we cleverly implement Implicit Announcement removal. * * if( b_need_delete ) * RemoveAnnounce( p_sd, p_sd->p_sys->pp_announces[i]); * else */ if( !b_need_delete ) { /* No need to go after six, as we start to trust the * average period at six */ if( p_announce->i_period_trust <= 5 ) p_announce->i_period_trust++; /* Compute the average period */ mtime_t now = mdate(); p_announce->i_period = (p_announce->i_period + (now - p_announce->i_last)) / 2; p_announce->i_last = now; } FreeSDP( p_sdp ); p_sdp = NULL; return VLC_SUCCESS; } } CreateAnnounce( p_sd, i_hash, p_sdp ); FREENULL (decomp); return VLC_SUCCESS;}sap_announce_t *CreateAnnounce( services_discovery_t *p_sd, uint16_t i_hash, sdp_t *p_sdp ){ input_item_t *p_input; const char *psz_value; sap_announce_t *p_sap = (sap_announce_t *)malloc( sizeof(sap_announce_t ) ); services_discovery_sys_t *p_sys; if( p_sap == NULL ) return NULL; p_sys = p_sd->p_sys; p_sap->i_last = mdate(); p_sap->i_period = 0; p_sap->i_period_trust = 0; p_sap->i_hash = i_hash; p_sap->p_sdp = p_sdp; /* Released in RemoveAnnounce */ p_input = input_item_NewWithType( VLC_OBJECT(p_sd), p_sap->p_sdp->psz_uri, p_sdp->psz_sessionname, 0, NULL, -1, ITEM_TYPE_NET ); p_sap->p_item = p_input; if( !p_input ) { free( p_sap ); return NULL; } if( p_sys->b_timeshift ) input_item_AddOption( p_input, ":access-filter=timeshift" ); psz_value = GetAttribute( p_sap->p_sdp->pp_attributes, p_sap->p_sdp->i_attributes, "tool" ); if( psz_value != NULL ) { input_item_AddInfo( p_input, _("Session"), _("Tool"), "%s", psz_value ); } if( strcmp( p_sdp->username, "-" ) ) { input_item_AddInfo( p_input, _("Session"), _("User"), "%s", p_sdp->username ); } /* Handle group */ 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" ); services_discovery_AddItem( p_sd, p_input, psz_value /* category name */ ); TAB_APPEND( p_sys->i_announces, p_sys->pp_announces, p_sap ); return p_sap;}static const char *FindAttribute (const sdp_t *sdp, unsigned media, const char *name){ /* Look for media attribute, and fallback to session */ return GetAttribute (sdp->mediav[media].pp_attributes, sdp->mediav[media].i_attributes, name) ?: GetAttribute (sdp->pp_attributes, sdp->i_attributes, name);}/* Fill p_sdp->psz_uri */static int ParseConnection( vlc_object_t *p_obj, sdp_t *p_sdp ){ 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->addr), p_sdp->mediav->addrlen, psz_uri + 1, sizeof (psz_uri) - 2, &port, NI_NUMERICHOST)) return VLC_EGENERIC; if (strchr (psz_uri + 1, ':')) { host = psz_uri; strcat (psz_uri, "]"); } else host = psz_uri + 1; /* Parse m= field */ char *sdp_proto = strdup (p_sdp->mediav[0].fmt); if (sdp_proto == NULL) return VLC_ENOMEM; char *subtype = strchr (sdp_proto, ' '); if (subtype == NULL) { msg_Dbg (p_obj, "missing SDP media subtype: %s", sdp_proto); free (sdp_proto); return VLC_EGENERIC; } else { *subtype++ = '\0'; /* FIXME: check for multiple payload types in RTP/AVP case. * FIXME: check for "mpeg" subtype in raw udp case. */ if (!strcasecmp (sdp_proto, "udp")) p_sdp->i_media_type = 33; else p_sdp->i_media_type = atoi (subtype); } /* RTP protocol, nul, VLC shortcut, nul, flags byte as follow: * 0x1: Connection-Oriented media. */ static const char proto_match[] = "udp\0" "udp\0\0" "RTP/AVP\0" "rtp\0\0" "UDPLite/RTP/AVP\0" "udplite\0\0" "DCCP/RTP/AVP\0" "dccp\0\1" "TCP/RTP/AVP\0" "rtptcp\0\1" "\0"; const char *vlc_proto = NULL; uint8_t flags = 0; for (const char *proto = proto_match; *proto;) { if (strcasecmp (proto, sdp_proto) == 0) { vlc_proto = proto + strlen (proto) + 1; flags = vlc_proto[strlen (vlc_proto) + 1]; break; } proto += strlen (proto) + 1; proto += strlen (proto) + 2; } free (sdp_proto); if (vlc_proto == NULL) { msg_Dbg (p_obj, "unknown SDP media protocol: %s", p_sdp->mediav[0].fmt); return VLC_EGENERIC; } if (flags & 1) { /* Connection-oriented media */ const char *setup = FindAttribute (p_sdp, 0, "setup"); if (setup == NULL) setup = "active"; /* default value */ if (strcmp (setup, "actpass") && strcmp (setup, "passive")) { msg_Dbg (p_obj, "unsupported COMEDIA mode: %s", setup); return VLC_EGENERIC; } if (asprintf (&p_sdp->psz_uri, "%s://%s:%d", vlc_proto, host, port) == -1) return VLC_ENOMEM; } else { /* Non-connected (normally multicast) media */ char psz_source[258] = ""; const char *sfilter = FindAttribute (p_sdp, 0, "source-filter"); if (sfilter != NULL) { char psz_source_ip[256]; unsigned ipv; if (sscanf (sfilter, " incl IN IP%u %*s %255s ", &ipv, psz_source_ip) == 2) { /* According to RFC4570, FQDNs can be used for source-filters, * but -seriously- this is impractical */ switch (ipv) {#ifdef AF_INET6 case 6: { struct in6_addr addr; if ((inet_pton (AF_INET6, psz_source_ip, &addr) > 0) && (inet_ntop (AF_INET6, &addr, psz_source + 1, sizeof (psz_source) - 2) != NULL)) { psz_source[0] = '['; psz_source[strlen (psz_source)] = ']'; } break; }#endif case 4: { struct in_addr addr; if ((inet_pton (AF_INET, psz_source_ip, &addr) > 0) && (inet_ntop (AF_INET, &addr, psz_source, sizeof (psz_source)) == NULL)) *psz_source = '\0'; break; } } } } if (asprintf (&p_sdp->psz_uri, "%s://%s@%s:%i", vlc_proto, psz_source, host, port) == -1) return VLC_ENOMEM; } return VLC_SUCCESS;}static int ParseSDPConnection (const char *str, struct sockaddr_storage *addr, socklen_t *addrlen, unsigned *number){ char host[60]; unsigned fam, n1, n2; int res = sscanf (str, "IN IP%u %59[^/]/%u/%u", &fam, host, &n1, &n2); if (res < 2) return -1; switch (fam) {#ifdef AF_INET6 case 6: addr->ss_family = AF_INET6;# ifdef HAVE_SA_LEN addr->ss_len =# endif *addrlen = sizeof (struct sockaddr_in6); if (inet_pton (AF_INET6, host, &((struct sockaddr_in6 *)addr)->sin6_addr) <= 0) return -1; *number = (res >= 3) ? n1 : 1; break;#endif case 4: addr->ss_family = AF_INET;# ifdef HAVE_SA_LEN addr->ss_len =# endif *addrlen = sizeof (struct sockaddr_in); if (inet_pton (AF_INET, host, &((struct sockaddr_in *)addr)->sin_addr) <= 0) return -1; *number = (res >= 4) ? n2 : 1; break; default: return -1; } return 0;}/*********************************************************************** * ParseSDP : SDP parsing * ********************************************************************* * Validate SDP and parse all fields ***********************************************************************/static sdp_t *ParseSDP (vlc_object_t *p_obj, const char *psz_sdp){ if( psz_sdp == NULL ) return NULL; sdp_t *p_sdp = calloc (1, sizeof (*p_sdp)); if (p_sdp == NULL) return NULL; char expect = 'V'; struct sockaddr_storage glob_addr; 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) { /* Extract one line */ char *eol = strchr (psz_sdp, '\n'); size_t linelen = eol ? (size_t)(eol - psz_sdp) : strlen (psz_sdp); char line[linelen + 1]; memcpy (line, psz_sdp, linelen); line[linelen] = '\0'; psz_sdp += linelen + 1; /* Remove carriage return if present */ eol = strchr (line, '\r'); if (eol != NULL) { linelen = eol - line; line[linelen] = '\0'; } /* Validate line */ char cat = line[0], *data = line + 2; if (!cat || (strchr ("vosiuepcbtrzkam", cat) == NULL)) { /* MUST ignore SDP with unknown line type */ msg_Dbg (p_obj, "unknown SDP line type: 0x%02x", (int)cat); goto error; } if (line[1] != '=') { msg_Dbg (p_obj, "invalid SDP line: %s", line); goto error; } assert (linelen >= 2); /* SDP parsing state machine * We INTERNALLY use uppercase for session, lowercase for media */ switch (expect) { /* Session description */ case 'V': expect = 'O'; if (cat != 'v') { msg_Dbg (p_obj, "missing SDP version");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -