]>
Commit | Line | Data |
---|---|---|
1 | #include <stdio.h> | |
2 | #include <stdlib.h> | |
3 | #include <sys/types.h> | |
4 | #include <sys/socket.h> | |
5 | #include <netinet/in.h> | |
6 | #include <arpa/inet.h> | |
7 | #include <sys/time.h> | |
8 | #include <time.h> | |
9 | #include <string.h> | |
10 | #include <strings.h> | |
11 | #include <unistd.h> | |
12 | #include <sys/select.h> | |
13 | ||
14 | #include "mcast.h" | |
15 | #include "sap.h" | |
16 | ||
17 | #define SAP_ADDR "224.2.127.254" | |
18 | #define SAP_PORT 9875 | |
19 | #define SAP_MAX_SIZE 1024 | |
20 | ||
21 | #define SAP_TIMEOUT 3 | |
22 | ||
23 | #define BUFFSIZE SAP_MAX_SIZE | |
24 | ||
25 | char *get_url_from_sap(char *service) | |
26 | { | |
27 | struct timeval start, curr; | |
28 | struct ip_mreq mreq; | |
29 | unsigned char buffer[BUFFSIZE]; | |
30 | char *url = NULL; | |
31 | int fd; | |
32 | ||
33 | snprintf(buffer,BUFFSIZE,"udp://%s:%u", SAP_ADDR, SAP_PORT); | |
34 | ||
35 | fd = open_mcast(buffer); | |
36 | ||
37 | gettimeofday(&start, NULL); | |
38 | ||
39 | do { | |
40 | int recvd; | |
41 | int sap_version, sap_addrtype, sap_messagetype, sap_encrypted, sap_compressed; | |
42 | in_addr_t sender_address; | |
43 | unsigned char auth_len; | |
44 | unsigned short msgid; | |
45 | unsigned char *payload, *pos, *host = NULL, *proto = NULL, *port = NULL, *sname = NULL; | |
46 | fd_set rfds; | |
47 | struct timeval tv; | |
48 | int retval; | |
49 | ||
50 | FD_ZERO(&rfds); | |
51 | FD_SET(fd, &rfds); | |
52 | ||
53 | tv.tv_sec = 0; | |
54 | tv.tv_usec = 100000; | |
55 | ||
56 | if ((retval = select(fd+1, &rfds, NULL, NULL, &tv)) == -1) { | |
57 | perror("select"); | |
58 | return NULL; | |
59 | } | |
60 | ||
61 | if (!retval) { | |
62 | gettimeofday(&curr, NULL); | |
63 | continue; | |
64 | } | |
65 | ||
66 | if ((recvd = recv(fd, buffer, BUFFSIZE, 0)) < 1) { | |
67 | perror("recv"); | |
68 | return NULL; | |
69 | } | |
70 | ||
71 | gettimeofday(&curr, NULL); | |
72 | ||
73 | sap_version = (buffer[0] >> 5) & 0x7; | |
74 | sap_addrtype = (buffer[0] >> 4) & 0x1; | |
75 | sap_messagetype = (buffer[0] >> 2) & 0x1; | |
76 | sap_encrypted = (buffer[0] >> 1) & 0x1; | |
77 | sap_compressed = buffer[0] & 0x1; | |
78 | auth_len = buffer[1]; | |
79 | msgid = buffer[2] << 8 | buffer[3]; | |
80 | memcpy(&sender_address, buffer+4, (sap_addrtype?16:4)); | |
81 | payload = buffer + 4 /* (sap_*, auth_len, msgid) */ + (sap_addrtype?16:4) + auth_len; | |
82 | ||
83 | #ifdef DEBUG | |
84 | printf("\n"); | |
85 | printf("SAP-Version: %d\n", sap_version); | |
86 | printf("Adresstyp: %s\n", (sap_addrtype?"IPv6":"IPv4")); | |
87 | printf("Messagetype: %s\n", (sap_messagetype?"Announcement":"Deletion")); | |
88 | printf("Encrypted: %d\n", sap_encrypted); | |
89 | printf("Compressed: %d\n", sap_compressed); | |
90 | printf("Authentication Length: %d\n", auth_len); | |
91 | printf("Sender: %u\n", sender_address); | |
92 | printf("Message Identifier Hash: %u\n", msgid); | |
93 | #endif | |
94 | ||
95 | if (sap_addrtype) | |
96 | continue; /* We don't support IPv6 for now */ | |
97 | ||
98 | #if 0 /* Getstream gets this wrong, see rfc2974 */ | |
99 | if (sap_messagetype) | |
100 | continue; /* We are not interested in deletions */ | |
101 | #endif | |
102 | ||
103 | if (sap_encrypted || sap_compressed) | |
104 | continue; | |
105 | ||
106 | /* RFC 2327 | |
107 | * v=0 | |
108 | * o=- 6dca 1 IN IP4 192.168.100.17:2000 | |
109 | * s=TV Das Erste | |
110 | * t=0 0 | |
111 | * c=IN IP4 192.168.100.17/1 | |
112 | * m=video 2000 http 33 | |
113 | * a=tool:getstream | |
114 | * a=type:broadcast | |
115 | */ | |
116 | ||
117 | pos = payload; | |
118 | while(*pos != 0 && (pos-buffer) < recvd) { | |
119 | if (*pos == 0x0d) | |
120 | *pos = 0; | |
121 | ||
122 | if (*pos == 0x0a) { | |
123 | *pos = 0; | |
124 | ||
125 | if (!strncasecmp("s=", payload, 2)) { | |
126 | sname = payload + 2; | |
127 | } else if (!strncasecmp("c=", payload, 2)) { | |
128 | int poscnt = 0; | |
129 | ||
130 | payload += 2; | |
131 | while (*payload != 0) { | |
132 | if (poscnt == 2 && *payload == '/') { | |
133 | *payload = 0; | |
134 | break; | |
135 | } | |
136 | ||
137 | if (*payload == ' ') { | |
138 | *payload = 0; | |
139 | poscnt++; | |
140 | ||
141 | /* c=<network type> <address type> <connection address> */ | |
142 | if (poscnt == 2) | |
143 | host = payload + 1; | |
144 | ||
145 | if (poscnt > 2) | |
146 | break; | |
147 | } | |
148 | payload++; | |
149 | } | |
150 | } else if (!strncasecmp("m=", payload, 2)) { | |
151 | int poscnt = 0; | |
152 | ||
153 | payload += 2; | |
154 | while (*payload != 0) { | |
155 | if (*payload == ' ') { | |
156 | *payload = 0; | |
157 | poscnt++; | |
158 | ||
159 | /* m=<media> <port> <transport> <fmt list> */ | |
160 | if (poscnt == 1) | |
161 | port = payload + 1; | |
162 | ||
163 | if (poscnt == 2) | |
164 | proto = payload + 1; | |
165 | ||
166 | if (poscnt > 2) | |
167 | break; | |
168 | } | |
169 | payload++; | |
170 | } | |
171 | } | |
172 | ||
173 | payload = ++pos; | |
174 | continue; | |
175 | } | |
176 | pos++; | |
177 | } | |
178 | ||
179 | if (sname && proto && port) { | |
180 | if (!host) { | |
181 | struct in_addr inaddr; | |
182 | ||
183 | inaddr.s_addr = sender_address; | |
184 | host = inet_ntoa(inaddr); | |
185 | } | |
186 | ||
187 | #ifdef DEBUG | |
188 | printf("%s -> %s://%s:%s\n", sname, proto, host, port); | |
189 | #endif | |
190 | ||
191 | if (strlen(service) < strlen(sname)) { | |
192 | sname += strlen(sname) - strlen(service); | |
193 | } | |
194 | ||
195 | if (!strncasecmp(service, sname, strlen(service))) { | |
196 | int len = strlen(host)+strlen(proto)+strlen(port)+5; | |
197 | ||
198 | if (!(url = malloc(len))) { | |
199 | perror("malloc"); | |
200 | return NULL; | |
201 | } | |
202 | ||
203 | snprintf(url, len, "%s://%s:%s", proto, host, port); | |
204 | url[len-1] = 0; | |
205 | break; | |
206 | } | |
207 | } | |
208 | ||
209 | } while(curr.tv_sec < start.tv_sec+SAP_TIMEOUT); | |
210 | ||
211 | mreq.imr_multiaddr.s_addr = inet_addr(SAP_ADDR); | |
212 | mreq.imr_interface.s_addr = INADDR_ANY; | |
213 | setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); | |
214 | ||
215 | close(fd); | |
216 | ||
217 | return url; | |
218 | } |