| 853 | | char *psz_proto = NULL; |
|---|
| 854 | | int i_port = 0; |
|---|
| 855 | | |
|---|
| 856 | | /* Parse c= field */ |
|---|
| 857 | | if( p_sdp->psz_connection ) |
|---|
| 858 | | { |
|---|
| 859 | | char hostname[1024]; |
|---|
| 860 | | int ipv; |
|---|
| 861 | | |
|---|
| 862 | | /* |
|---|
| 863 | | * NOTE: we ignore the TTL parameter on-purpose, as some SAP |
|---|
| 864 | | * advertisers don't include it (and it is utterly useless). |
|---|
| 865 | | */ |
|---|
| 866 | | if (sscanf (p_sdp->psz_connection, "IN IP%d %1023[^/]", &ipv, |
|---|
| 867 | | hostname) != 2) |
|---|
| 868 | | { |
|---|
| 869 | | msg_Warn (p_obj, "unable to parse c field: \"%s\"", |
|---|
| 870 | | p_sdp->psz_connection); |
|---|
| 871 | | return VLC_EGENERIC; |
|---|
| 872 | | } |
|---|
| 873 | | |
|---|
| 874 | | switch (ipv) |
|---|
| 875 | | { |
|---|
| 876 | | case 4: |
|---|
| 877 | | case 6: |
|---|
| 878 | | break; |
|---|
| 879 | | |
|---|
| 880 | | default: |
|---|
| 881 | | msg_Warn (p_obj, "unknown IP version %d", ipv); |
|---|
| 882 | | return VLC_EGENERIC; |
|---|
| 883 | | } |
|---|
| 884 | | |
|---|
| 885 | | if (strchr (hostname, ':') != NULL) |
|---|
| 886 | | sprintf (psz_uri, "[%s]", hostname); |
|---|
| 887 | | else |
|---|
| 888 | | strcpy (psz_uri, hostname); |
|---|
| 889 | | } |
|---|
| | 846 | const char *host; |
|---|
| | 847 | int port; |
|---|
| | 848 | |
|---|
| | 849 | psz_uri[0] = '['; |
|---|
| | 850 | if (vlc_getnameinfo ((struct sockaddr *)&(p_sdp->mediav[0].addr), |
|---|
| | 851 | p_sdp->mediav[0].addrlen, psz_uri + 1, |
|---|
| | 852 | sizeof (psz_uri) - 2, &port, NI_NUMERICHOST)) |
|---|
| | 853 | return VLC_EGENERIC; |
|---|
| | 854 | |
|---|
| | 855 | if (strchr (psz_uri + 1, ':')) |
|---|
| | 856 | { |
|---|
| | 857 | host = psz_uri; |
|---|
| | 858 | psz_uri[strlen (psz_uri)] = ']'; |
|---|
| | 859 | } |
|---|
| | 860 | else |
|---|
| | 861 | host = psz_uri + 1; |
|---|
| 892 | | if( p_sdp->psz_media ) |
|---|
| 893 | | { |
|---|
| 894 | | psz_parse = p_sdp->psz_media; |
|---|
| 895 | | |
|---|
| 896 | | psz_eof = strchr( psz_parse, ' ' ); |
|---|
| 897 | | |
|---|
| 898 | | if( psz_eof ) |
|---|
| 899 | | { |
|---|
| 900 | | *psz_eof = '\0'; |
|---|
| 901 | | |
|---|
| 902 | | /* |
|---|
| 903 | | * That's ugly. We should go through every media, and make sure |
|---|
| 904 | | * at least one of them is audio or video. In the mean time, I |
|---|
| 905 | | * need to accept data too. |
|---|
| 906 | | */ |
|---|
| 907 | | if( strncmp( psz_parse, "audio", 5 ) |
|---|
| 908 | | && strncmp( psz_parse, "video", 5 ) |
|---|
| 909 | | && strncmp( psz_parse, "data", 4 ) ) |
|---|
| 910 | | { |
|---|
| 911 | | msg_Warn( p_obj, "unhandled media type \"%s\"", psz_parse ); |
|---|
| 912 | | return VLC_EGENERIC; |
|---|
| 913 | | } |
|---|
| 914 | | |
|---|
| 915 | | psz_parse = psz_eof + 1; |
|---|
| 916 | | } |
|---|
| 917 | | else |
|---|
| 918 | | { |
|---|
| 919 | | msg_Warn( p_obj, "unable to parse m field (1)"); |
|---|
| 920 | | return VLC_EGENERIC; |
|---|
| 921 | | } |
|---|
| 922 | | |
|---|
| 923 | | psz_eof = strchr( psz_parse, ' ' ); |
|---|
| 924 | | |
|---|
| 925 | | if( psz_eof ) |
|---|
| 926 | | { |
|---|
| 927 | | *psz_eof = '\0'; |
|---|
| 928 | | |
|---|
| 929 | | /* FIXME : multiple port ! */ |
|---|
| 930 | | i_port = atoi( psz_parse ); |
|---|
| 931 | | |
|---|
| 932 | | if( i_port <= 0 || i_port >= 65536 ) |
|---|
| 933 | | { |
|---|
| 934 | | msg_Warn( p_obj, "invalid transport port %i", i_port ); |
|---|
| 935 | | } |
|---|
| 936 | | |
|---|
| 937 | | psz_parse = psz_eof + 1; |
|---|
| 938 | | } |
|---|
| 939 | | else |
|---|
| 940 | | { |
|---|
| 941 | | msg_Warn( p_obj, "unable to parse m field (2)"); |
|---|
| 942 | | return VLC_EGENERIC; |
|---|
| 943 | | } |
|---|
| 944 | | |
|---|
| 945 | | psz_eof = strchr( psz_parse, ' ' ); |
|---|
| 946 | | |
|---|
| 947 | | if( psz_eof ) |
|---|
| 948 | | { |
|---|
| 949 | | *psz_eof = '\0'; |
|---|
| 950 | | psz_proto = strdup( psz_parse ); |
|---|
| 951 | | |
|---|
| 952 | | psz_parse = psz_eof + 1; |
|---|
| 953 | | p_sdp->i_media_type = atoi( psz_parse ); |
|---|
| 954 | | |
|---|
| 955 | | } |
|---|
| 956 | | else |
|---|
| 957 | | { |
|---|
| 958 | | msg_Dbg( p_obj, "incorrect m field, %s", p_sdp->psz_media ); |
|---|
| 959 | | p_sdp->i_media_type = 33; |
|---|
| 960 | | psz_proto = strdup( psz_parse ); |
|---|
| 961 | | } |
|---|
| 962 | | } |
|---|
| 963 | | |
|---|
| 964 | | if( psz_proto && !strncmp( psz_proto, "RTP/AVP", 7 ) ) |
|---|
| 965 | | { |
|---|
| 966 | | free( psz_proto ); |
|---|
| 967 | | psz_proto = strdup( "rtp" ); |
|---|
| 968 | | } |
|---|
| 969 | | if( psz_proto && !strncasecmp( psz_proto, "UDP", 3 ) ) |
|---|
| 970 | | { |
|---|
| 971 | | free( psz_proto ); |
|---|
| 972 | | psz_proto = strdup( "udp" ); |
|---|
| 973 | | } |
|---|
| 974 | | |
|---|
| 975 | | if( i_port == 0 ) |
|---|
| 976 | | { |
|---|
| 977 | | i_port = 1234; |
|---|
| | 864 | char *sdp_proto = strdup (p_sdp->mediav[0].fmt); |
|---|
| | 865 | if (sdp_proto == NULL) |
|---|
| | 866 | return VLC_ENOMEM; |
|---|
| | 867 | |
|---|
| | 868 | char *subtype = strchr (sdp_proto, ' '); |
|---|
| | 869 | if (sdp_proto == NULL) |
|---|
| | 870 | { |
|---|
| | 871 | msg_Dbg (p_obj, "missing SDP media subtype: %s", sdp_proto); |
|---|
| | 872 | p_sdp->i_media_type = 0; |
|---|
| | 873 | } |
|---|
| | 874 | else |
|---|
| | 875 | { |
|---|
| | 876 | *subtype++ = '\0'; |
|---|
| | 877 | p_sdp->i_media_type = atoi (subtype); |
|---|
| | 878 | } |
|---|
| | 879 | if (p_sdp->i_media_type == 0) |
|---|
| | 880 | p_sdp->i_media_type = 33; |
|---|
| | 881 | |
|---|
| | 882 | static const char proto_match[] = |
|---|
| | 883 | "udp\0" "udp\0" |
|---|
| | 884 | "RTP/AVP\0" "rtp\0" |
|---|
| | 885 | "UDPLite/RTP/AVP\0" "udplite\0" |
|---|
| | 886 | "DCCP/RTP/AVP\0" "dccp\0" |
|---|
| | 887 | "TCP/RTP/AVP\0" "tcp\0" |
|---|
| | 888 | "\0"; |
|---|
| | 889 | |
|---|
| | 890 | const char *vlc_proto = NULL; |
|---|
| | 891 | for (const char *proto = proto_match; *proto;) |
|---|
| | 892 | { |
|---|
| | 893 | if (strcasecmp (proto, sdp_proto)) |
|---|
| | 894 | { |
|---|
| | 895 | vlc_proto = proto + strlen (proto) + 1; |
|---|
| | 896 | break; |
|---|
| | 897 | } |
|---|
| | 898 | proto += strlen (proto) + 1; |
|---|
| | 899 | proto += strlen (proto) + 1; |
|---|
| | 900 | } |
|---|
| | 901 | |
|---|
| | 902 | free (sdp_proto); |
|---|
| | 903 | if (vlc_proto == NULL) |
|---|
| | 904 | { |
|---|
| | 905 | msg_Dbg (p_obj, "unknown SDP media protocol: %s", |
|---|
| | 906 | p_sdp->mediav[0].fmt); |
|---|
| | 907 | return VLC_EGENERIC; |
|---|
| | 937 | |
|---|
| | 938 | |
|---|
| | 939 | static int ParseSDPConnection (const char *str, struct sockaddr_storage *addr, |
|---|
| | 940 | socklen_t *addrlen, unsigned *number) |
|---|
| | 941 | { |
|---|
| | 942 | char host[60]; |
|---|
| | 943 | unsigned fam, n1, n2; |
|---|
| | 944 | |
|---|
| | 945 | int res = sscanf (str, "IN IP%u %59[^/]/%u/%u", &fam, host, &n1, &n2); |
|---|
| | 946 | if (res < 2) |
|---|
| | 947 | return -1; |
|---|
| | 948 | |
|---|
| | 949 | switch (fam) |
|---|
| | 950 | { |
|---|
| | 951 | #ifdef AF_INET6 |
|---|
| | 952 | case 6: |
|---|
| | 953 | addr->ss_family = AF_INET6; |
|---|
| | 954 | # ifdef HAVE_SA_LEN |
|---|
| | 955 | addr->ss_len = |
|---|
| | 956 | # endif |
|---|
| | 957 | *addrlen = sizeof (struct sockaddr_in6); |
|---|
| | 958 | |
|---|
| | 959 | if (inet_pton (AF_INET6, host, |
|---|
| | 960 | &((struct sockaddr_in6 *)addr)->sin6_addr) <= 0) |
|---|
| | 961 | return -1; |
|---|
| | 962 | |
|---|
| | 963 | *number = (res >= 3) ? n1 : 1; |
|---|
| | 964 | break; |
|---|
| | 965 | #endif |
|---|
| | 966 | |
|---|
| | 967 | case 4: |
|---|
| | 968 | addr->ss_family = AF_INET; |
|---|
| | 969 | # ifdef HAVE_SA_LEN |
|---|
| | 970 | addr->ss_len = |
|---|
| | 971 | # endif |
|---|
| | 972 | *addrlen = sizeof (struct sockaddr_in); |
|---|
| | 973 | |
|---|
| | 974 | if (inet_pton (AF_INET, host, |
|---|
| | 975 | &((struct sockaddr_in *)addr)->sin_addr) <= 0) |
|---|
| | 976 | return -1; |
|---|
| | 977 | |
|---|
| | 978 | *number = (res >= 4) ? n2 : 1; |
|---|
| | 979 | break; |
|---|
| | 980 | |
|---|
| | 981 | default: |
|---|
| | 982 | return -1; |
|---|
| | 983 | } |
|---|
| | 984 | return 0; |
|---|
| | 985 | } |
|---|
| | 986 | |
|---|
| 1022 | | } |
|---|
| 1023 | | |
|---|
| 1024 | | p_sdp = (sdp_t *)malloc( sizeof( sdp_t ) ); |
|---|
| 1025 | | if( p_sdp == NULL ) |
|---|
| 1026 | | return NULL; |
|---|
| 1027 | | |
|---|
| 1028 | | /* init to 0 */ |
|---|
| 1029 | | memset( p_sdp, 0, sizeof( sdp_t ) ); |
|---|
| 1030 | | |
|---|
| 1031 | | p_sdp->psz_sdp = strdup( psz_sdp ); |
|---|
| 1032 | | if( p_sdp->psz_sdp == NULL ) |
|---|
| 1033 | | { |
|---|
| 1034 | | free( p_sdp ); |
|---|
| 1035 | | return NULL; |
|---|
| 1036 | | } |
|---|
| 1037 | | |
|---|
| 1038 | | while( *psz_sdp != '\0' && b_end == VLC_FALSE ) |
|---|
| 1039 | | { |
|---|
| 1040 | | char *psz_eol = NULL; |
|---|
| 1041 | | char *psz_eof = NULL; |
|---|
| 1042 | | char *psz_parse = NULL; |
|---|
| 1043 | | char *psz_sess_id = NULL; |
|---|
| 1044 | | |
|---|
| 1045 | | while( *psz_sdp == '\r' || *psz_sdp == '\n' || |
|---|
| 1046 | | *psz_sdp == ' ' || *psz_sdp == '\t' ) |
|---|
| 1047 | | { |
|---|
| 1048 | | psz_sdp++; |
|---|
| 1049 | | } |
|---|
| 1050 | | |
|---|
| 1051 | | if( ( psz_eol = strchr( psz_sdp, '\n' ) ) == NULL ) |
|---|
| 1052 | | { |
|---|
| 1053 | | psz_eol = (char *)psz_sdp + strlen( psz_sdp ); |
|---|
| 1054 | | b_end = VLC_TRUE; |
|---|
| 1055 | | } |
|---|
| 1056 | | if( psz_eol > psz_sdp && *( psz_eol - 1 ) == '\r' ) |
|---|
| 1057 | | { |
|---|
| 1058 | | psz_eol--; |
|---|
| 1059 | | } |
|---|
| 1060 | | |
|---|
| 1061 | | if( psz_eol <= psz_sdp ) |
|---|
| 1062 | | { |
|---|
| 1063 | | break; |
|---|
| 1064 | | } |
|---|
| 1065 | | *psz_eol++ = '\0'; |
|---|
| 1066 | | |
|---|
| 1067 | | /* no space allowed between fields */ |
|---|
| 1068 | | if( psz_sdp[1] != '=' ) |
|---|
| 1069 | | { |
|---|
| 1070 | | msg_Warn( p_obj, "invalid packet" ) ; |
|---|
| 1071 | | FreeSDP( p_sdp ); p_sdp = NULL; |
|---|
| 1072 | | return NULL; |
|---|
| 1073 | | } |
|---|
| 1074 | | |
|---|
| 1075 | | /* Now parse each line */ |
|---|
| 1076 | | switch( psz_sdp[0] ) |
|---|
| 1077 | | { |
|---|
| 1078 | | case( 'v' ): |
|---|
| | 1001 | |
|---|
| | 1002 | char expect = 'V'; |
|---|
| | 1003 | struct sockaddr_storage glob_addr; |
|---|
| | 1004 | memset (&glob_addr, 0, sizeof (glob_addr)); |
|---|
| | 1005 | socklen_t glob_len = 0; |
|---|
| | 1006 | unsigned glob_count = 1; |
|---|
| | 1007 | |
|---|
| | 1008 | /* TODO: use iconv and charset attribute instead of EnsureUTF8 */ |
|---|
| | 1009 | while (*psz_sdp) |
|---|
| | 1010 | { |
|---|
| | 1011 | /* Extract one line */ |
|---|
| | 1012 | char *eol = strchr (psz_sdp, '\n'); |
|---|
| | 1013 | size_t linelen = eol ? (size_t)(eol - psz_sdp) : strlen (psz_sdp); |
|---|
| | 1014 | char line[linelen + 1]; |
|---|
| | 1015 | memcpy (line, psz_sdp, linelen); |
|---|
| | 1016 | line[linelen] = '\0'; |
|---|
| | 1017 | |
|---|
| | 1018 | psz_sdp += linelen + 1; |
|---|
| | 1019 | |
|---|
| | 1020 | /* Remove carriage return if present */ |
|---|
| | 1021 | eol = strchr (line, '\r'); |
|---|
| | 1022 | if (eol != NULL) |
|---|
| | 1023 | { |
|---|
| | 1024 | linelen = eol - line; |
|---|
| | 1025 | line[linelen] = '\0'; |
|---|
| | 1026 | } |
|---|
| | 1027 | |
|---|
| | 1028 | /* Validate line */ |
|---|
| | 1029 | char cat = line[0], *data = line + 2; |
|---|
| | 1030 | if (!cat || (strchr ("vosiuepcbtrzkam", cat) == NULL)) |
|---|
| | 1031 | { |
|---|
| | 1032 | /* MUST ignore SDP with unknown line type */ |
|---|
| | 1033 | msg_Dbg (p_obj, "unknown SDP line type: 0x%02x", (int)cat); |
|---|
| | 1034 | goto error; |
|---|
| | 1035 | } |
|---|
| | 1036 | if (line[1] != '=') |
|---|
| | 1037 | { |
|---|
| | 1038 | msg_Dbg (p_obj, "invalid SDP line: %s", line); |
|---|
| | 1039 | goto error; |
|---|
| | 1040 | } |
|---|
| | 1041 | |
|---|
| | 1042 | assert (linelen >= 2); |
|---|
| | 1043 | |
|---|
| | 1044 | /* SDP parsing state machine |
|---|
| | 1045 | * We INTERNALLY use uppercase for session, lowercase for media |
|---|
| | 1046 | */ |
|---|
| | 1047 | switch (expect) |
|---|
| | 1048 | { |
|---|
| | 1049 | /* Session description */ |
|---|
| | 1050 | case 'V': |
|---|
| | 1051 | expect = 'O'; |
|---|
| | 1052 | if (cat != 'v') |
|---|
| | 1053 | { |
|---|
| | 1054 | msg_Dbg (p_obj, "missing SDP version"); |
|---|
| | 1055 | goto error; |
|---|
| | 1056 | } |
|---|
| | 1057 | if (strcmp (data, "0")) |
|---|
| | 1058 | { |
|---|
| | 1059 | msg_Dbg (p_obj, "unknown SDP version: %s", data); |
|---|
| | 1060 | goto error; |
|---|
| | 1061 | } |
|---|
| 1085 | | int i_field = 0; |
|---|
| 1086 | | /* o field is <username> <session id> <version> |
|---|
| 1087 | | * <network type> <address type> <address> */ |
|---|
| 1088 | | |
|---|
| 1089 | | #define GET_FIELD( store ) \ |
|---|
| 1090 | | psz_eof = strchr( psz_parse, ' ' ); \ |
|---|
| 1091 | | if( psz_eof ) \ |
|---|
| 1092 | | { \ |
|---|
| 1093 | | *psz_eof=0; store = strdup( psz_parse ); \ |
|---|
| 1094 | | } \ |
|---|
| 1095 | | else \ |
|---|
| 1096 | | { \ |
|---|
| 1097 | | if( i_field != 5 ) \ |
|---|
| 1098 | | { \ |
|---|
| 1099 | | b_invalid = VLC_TRUE; break; \ |
|---|
| 1100 | | } \ |
|---|
| 1101 | | else \ |
|---|
| 1102 | | { \ |
|---|
| 1103 | | store = strdup( psz_parse ); \ |
|---|
| 1104 | | } \ |
|---|
| 1105 | | }; \ |
|---|
| 1106 | | psz_parse = psz_eof + 1; i_field++; |
|---|
| 1107 | | |
|---|
| 1108 | | |
|---|
| 1109 | | psz_parse = (char *)&psz_sdp[2]; |
|---|
| 1110 | | GET_FIELD( p_sdp->psz_username ); |
|---|
| 1111 | | GET_FIELD( psz_sess_id ); |
|---|
| 1112 | | |
|---|
| 1113 | | p_sdp->i_session_id = atoll( psz_sess_id ); |
|---|
| 1114 | | |
|---|
| 1115 | | FREENULL( psz_sess_id ); |
|---|
| 1116 | | |
|---|
| 1117 | | GET_FIELD( psz_sess_id ); |
|---|
| 1118 | | FREENULL( psz_sess_id ); |
|---|
| 1119 | | |
|---|
| 1120 | | GET_FIELD( p_sdp->psz_network_type ); |
|---|
| 1121 | | GET_FIELD( p_sdp->psz_address_type ); |
|---|
| 1122 | | GET_FIELD( p_sdp->psz_address ); |
|---|
| 1123 | | |
|---|
| | 1066 | expect = 'S'; |
|---|
| | 1067 | if (cat != 'o') |
|---|
| | 1068 | { |
|---|
| | 1069 | msg_Dbg (p_obj, "missing SDP originator"); |
|---|
| | 1070 | goto error; |
|---|
| | 1071 | } |
|---|
| | 1072 | |
|---|
| | 1073 | if ((sscanf (data, "%63s "I64Fu" "I64Fu" IN IP%u %1023s", |
|---|
| | 1074 | p_sdp->username, &p_sdp->session_id, |
|---|
| | 1075 | &p_sdp->session_version, &p_sdp->orig_ip_version, |
|---|
| | 1076 | p_sdp->orig_host) != 5) |
|---|
| | 1077 | || ((p_sdp->orig_ip_version != 4) |
|---|
| | 1078 | && (p_sdp->orig_ip_version != 6))) |
|---|
| | 1079 | { |
|---|
| | 1080 | msg_Dbg (p_obj, "SDP origin not supported: %s\n", data); |
|---|
| | 1081 | /* Or maybe out-of-range, but this looks suspicious */ |
|---|
| | 1082 | return NULL; |
|---|
| | 1083 | } |
|---|
| | 1084 | EnsureUTF8 (p_sdp->orig_host); |
|---|
| 1135 | | char *psz_eon = strchr( &psz_sdp[2], ':' ); |
|---|
| 1136 | | attribute_t *p_attr = malloc( sizeof( attribute_t ) ); |
|---|
| 1137 | | |
|---|
| 1138 | | /* Attribute with value */ |
|---|
| 1139 | | if( psz_eon ) |
|---|
| 1140 | | { |
|---|
| 1141 | | *psz_eon++ = '\0'; |
|---|
| 1142 | | |
|---|
| 1143 | | p_attr->psz_field = strdup( &psz_sdp[2] ); |
|---|
| 1144 | | p_attr->psz_value = strdup( psz_eon ); |
|---|
| 1145 | | } |
|---|
| 1146 | | else /* Attribute without value */ |
|---|
| 1147 | | { |
|---|
| 1148 | | p_attr->psz_field = strdup( &psz_sdp[2] ); |
|---|
| 1149 | | p_attr->psz_value = NULL; |
|---|
| 1150 | | } |
|---|
| 1151 | | |
|---|
| 1152 | | TAB_APPEND( p_sdp->i_attributes, p_sdp->pp_attributes, p_attr ); |
|---|
| | 1090 | expect = 'I'; |
|---|
| | 1091 | if ((cat != 's') || !*data) |
|---|
| | 1092 | { |
|---|
| | 1093 | /* MUST be present AND non-empty */ |
|---|
| | 1094 | msg_Dbg (p_obj, "missing SDP session name"); |
|---|
| | 1095 | goto error; |
|---|
| | 1096 | } |
|---|
| | 1097 | assert (p_sdp->psz_sessionname == NULL); // no memleak here |
|---|
| | 1098 | p_sdp->psz_sessionname = strdup (data); |
|---|
| | 1099 | EnsureUTF8 (p_sdp->psz_sessionname); |
|---|
| | 1100 | if (p_sdp->psz_sessionname == NULL) |
|---|
| | 1101 | goto error; |
|---|
| 1158 | | /* If we have several medias, we pass the announcement to |
|---|
| 1159 | | * LIVE.COM, so just count them */ |
|---|
| 1160 | | p_sdp->i_media++; |
|---|
| 1161 | | if( p_sdp->i_media == 1 ) |
|---|
| 1162 | | { |
|---|
| 1163 | | p_sdp->psz_media = strdup( &psz_sdp[2] ); |
|---|
| 1164 | | } |
|---|
| | 1171 | expect = 'i'; |
|---|
| | 1172 | if (cat != 'm') |
|---|
| | 1173 | { |
|---|
| | 1174 | msg_Dbg (p_obj, "missing SDP media description"); |
|---|
| | 1175 | goto error; |
|---|
| | 1176 | } |
|---|
| | 1177 | struct sdp_media_t *m = p_sdp->mediav + p_sdp->mediac; |
|---|
| | 1178 | |
|---|
| | 1179 | memcpy (&m->addr, &glob_addr, m->addrlen = glob_len); |
|---|
| | 1180 | m->n_addr = glob_count; |
|---|
| | 1181 | |
|---|
| | 1182 | /* TODO: remember media type (if we need multiple medias) */ |
|---|
| | 1183 | data = strchr (data, ' '); |
|---|
| | 1184 | if (data == NULL) |
|---|
| | 1185 | { |
|---|
| | 1186 | msg_Dbg (p_obj, "missing SDP media port"); |
|---|
| | 1187 | goto error; |
|---|
| | 1188 | } |
|---|
| | 1189 | int port = atoi (data); |
|---|
| | 1190 | if (port <= 0 || port >= 65536) |
|---|
| | 1191 | { |
|---|
| | 1192 | msg_Dbg (p_obj, "invalid transport port %d", port); |
|---|
| | 1193 | goto error; |
|---|
| | 1194 | } |
|---|
| | 1195 | net_SetPort ((struct sockaddr *)&m->addr, htons (port)); |
|---|
| | 1196 | |
|---|
| | 1197 | data = strchr (data, ' '); |
|---|
| | 1198 | if (data == NULL) |
|---|
| | 1199 | { |
|---|
| | 1200 | msg_Dbg (p_obj, "missing SDP media format"); |
|---|
| | 1201 | goto error; |
|---|
| | 1202 | } |
|---|
| | 1203 | m->fmt = strdup (data); |
|---|
| | 1204 | if (m->fmt == NULL) |
|---|
| | 1205 | goto error; |
|---|
| | 1206 | |
|---|
| | 1207 | p_sdp->mediac++; |
|---|
| 1172 | | |
|---|
| 1173 | | p_sdp->psz_connection = strdup( &psz_sdp[2] ); |
|---|
| | 1214 | case 'c': |
|---|
| | 1215 | expect = 'b'; |
|---|
| | 1216 | if (cat == 'c') |
|---|
| | 1217 | { |
|---|
| | 1218 | struct sdp_media_t *m = p_sdp->mediav + p_sdp->mediac; |
|---|
| | 1219 | if (ParseSDPConnection (data, &m->addr, &m->addrlen, |
|---|
| | 1220 | &m->n_addr)) |
|---|
| | 1221 | { |
|---|
| | 1222 | msg_Dbg (p_obj, "SDP connection infos not supported: " |
|---|
| | 1223 | "%s", data); |
|---|
| | 1224 | goto error; |
|---|
| | 1225 | } |
|---|
| | 1226 | break; |
|---|
| | 1227 | } |
|---|
| | 1228 | case 'b': |
|---|
| | 1229 | expect = 'b'; |
|---|
| | 1230 | if (cat == 'b') |
|---|
| | 1231 | break; |
|---|
| | 1232 | case 'k': |
|---|
| | 1233 | expect = 'a'; |
|---|
| | 1234 | if (cat == 'k') |
|---|
| | 1235 | break; |
|---|
| | 1236 | case 'a': |
|---|
| | 1237 | assert (expect == 'a'); |
|---|
| | 1238 | if (cat == 'a') |
|---|
| | 1239 | { |
|---|
| | 1240 | attribute_t *p_attr = MakeAttribute (data); |
|---|
| | 1241 | if (p_attr == NULL) |
|---|
| | 1242 | goto error; |
|---|
| | 1243 | |
|---|
| | 1244 | TAB_APPEND (p_sdp->mediav[p_sdp->mediac - 1].i_attributes, |
|---|
| | 1245 | p_sdp->mediav[p_sdp->mediac - 1].pp_attributes, p_attr); |
|---|
| | 1246 | break; |
|---|
| | 1247 | } |
|---|
| | 1248 | |
|---|
| | 1249 | if (cat == 'm') |
|---|
| | 1250 | { |
|---|
| | 1251 | /* TODO */ |
|---|
| | 1252 | msg_Dbg (p_obj, "multi-media SDP not implemented -> live555"); |
|---|
| | 1253 | goto error; |
|---|
| | 1254 | } |
|---|
| | 1255 | |
|---|
| | 1256 | if (cat != 'm') |
|---|
| | 1257 | { |
|---|
| | 1258 | msg_Dbg (p_obj, "unexpected SDP line: 0x%02x", (int)cat); |
|---|
| | 1259 | goto error; |
|---|
| | 1260 | } |
|---|
| 1262 | | FREENULL( p_sdp->psz_username ); |
|---|
| 1263 | | FREENULL( p_sdp->psz_network_type ); |
|---|
| 1264 | | |
|---|
| 1265 | | FREENULL( p_sdp->psz_address ); |
|---|
| 1266 | | FREENULL( p_sdp->psz_address_type ); |
|---|
| 1267 | | |
|---|
| 1268 | | for( i= p_sdp->i_attributes - 1; i >= 0 ; i-- ) |
|---|
| 1269 | | { |
|---|
| 1270 | | struct attribute_t *p_attr = p_sdp->pp_attributes[i]; |
|---|
| 1271 | | FREENULL( p_sdp->pp_attributes[i]->psz_field ); |
|---|
| 1272 | | FREENULL( p_sdp->pp_attributes[i]->psz_value ); |
|---|
| 1273 | | REMOVE_ELEM( p_sdp->pp_attributes, p_sdp->i_attributes, i); |
|---|
| 1274 | | FREENULL( p_attr ); |
|---|
| 1275 | | } |
|---|
| 1276 | | FREENULL( p_sdp ); |
|---|
| | 1342 | |
|---|
| | 1343 | for (unsigned j = 0; j < p_sdp->mediac; j++) |
|---|
| | 1344 | { |
|---|
| | 1345 | free (p_sdp->mediav[j].fmt); |
|---|
| | 1346 | for (int i = 0; i < p_sdp->mediav[j].i_attributes; i++) |
|---|
| | 1347 | FreeAttribute (p_sdp->mediav[j].pp_attributes[i]); |
|---|
| | 1348 | } |
|---|
| | 1349 | |
|---|
| | 1350 | for (int i = 0; i < p_sdp->i_attributes; i++) |
|---|
| | 1351 | FreeAttribute (p_sdp->pp_attributes[i]); |
|---|
| | 1352 | |
|---|
| | 1353 | free (p_sdp->pp_attributes); |
|---|
| | 1354 | free (p_sdp); |
|---|
| 1311 | | * username, session_id, network type, address type and address */ |
|---|
| 1312 | | if( p_sdp1->psz_username && p_sdp2->psz_username && |
|---|
| 1313 | | p_sdp1->psz_network_type && p_sdp2->psz_network_type && |
|---|
| 1314 | | p_sdp1->psz_address_type && p_sdp2->psz_address_type && |
|---|
| 1315 | | p_sdp1->psz_address && p_sdp2->psz_address ) |
|---|
| 1316 | | { |
|---|
| 1317 | | if(!strcmp( p_sdp1->psz_username , p_sdp2->psz_username ) && |
|---|
| 1318 | | !strcmp( p_sdp1->psz_network_type , p_sdp2->psz_network_type ) && |
|---|
| 1319 | | !strcmp( p_sdp1->psz_address_type , p_sdp2->psz_address_type ) && |
|---|
| 1320 | | !strcmp( p_sdp1->psz_address , p_sdp2->psz_address ) && |
|---|
| 1321 | | p_sdp1->i_session_id == p_sdp2->i_session_id ) |
|---|
| 1322 | | { |
|---|
| 1323 | | return VLC_TRUE; |
|---|
| 1324 | | } |
|---|
| 1325 | | else |
|---|
| 1326 | | { |
|---|
| 1327 | | return VLC_FALSE; |
|---|
| 1328 | | } |
|---|
| | 1389 | * - username, |
|---|
| | 1390 | * - session_id, |
|---|
| | 1391 | * - network type (which is always IN), |
|---|
| | 1392 | * - address type (currently, this means IP version), |
|---|
| | 1393 | * - and hostname. |
|---|
| | 1394 | */ |
|---|
| | 1395 | if (strcmp (p_sdp1->username, p_sdp2->username) |
|---|
| | 1396 | || (p_sdp1->session_id != p_sdp2->session_id) |
|---|
| | 1397 | || (p_sdp1->orig_ip_version != p_sdp2->orig_ip_version) |
|---|
| | 1398 | || strcmp (p_sdp1->orig_host, p_sdp2->orig_host)) |
|---|
| | 1399 | return VLC_FALSE; |
|---|
| | 1400 | |
|---|
| | 1401 | return VLC_TRUE; |
|---|
| | 1402 | } |
|---|
| | 1403 | |
|---|
| | 1404 | |
|---|
| | 1405 | static inline attribute_t *MakeAttribute (const char *str) |
|---|
| | 1406 | { |
|---|
| | 1407 | attribute_t *a = malloc (sizeof (*a) + strlen (str) + 1); |
|---|
| | 1408 | if (a == NULL) |
|---|
| | 1409 | return NULL; |
|---|
| | 1410 | |
|---|
| | 1411 | strcpy (a->name, str); |
|---|
| | 1412 | EnsureUTF8 (a->name); |
|---|
| | 1413 | char *value = strchr (a->name, ':'); |
|---|
| | 1414 | if (value != NULL) |
|---|
| | 1415 | { |
|---|
| | 1416 | *value++ = '\0'; |
|---|
| | 1417 | a->value = value; |
|---|