8447845f |
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> |
89ec024f |
11 | #include <unistd.h> |
12 | #include <sys/select.h> |
8447845f |
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; |
89ec024f |
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; |
d5b58906 |
54 | tv.tv_usec = 100000; |
89ec024f |
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 | } |
8447845f |
65 | |
dacdaa20 |
66 | bzero(buffer, BUFFSIZE); |
8447845f |
67 | if ((recvd = recv(fd, buffer, BUFFSIZE, 0)) < 1) { |
68 | perror("recv"); |
69 | return NULL; |
70 | } |
71 | |
72 | gettimeofday(&curr, NULL); |
73 | |
74 | sap_version = (buffer[0] >> 5) & 0x7; |
75 | sap_addrtype = (buffer[0] >> 4) & 0x1; |
76 | sap_messagetype = (buffer[0] >> 2) & 0x1; |
77 | sap_encrypted = (buffer[0] >> 1) & 0x1; |
78 | sap_compressed = buffer[0] & 0x1; |
79 | auth_len = buffer[1]; |
80 | msgid = buffer[2] << 8 | buffer[3]; |
81 | memcpy(&sender_address, buffer+4, (sap_addrtype?16:4)); |
82 | payload = buffer + 4 /* (sap_*, auth_len, msgid) */ + (sap_addrtype?16:4) + auth_len; |
83 | |
84 | #ifdef DEBUG |
85 | printf("\n"); |
86 | printf("SAP-Version: %d\n", sap_version); |
87 | printf("Adresstyp: %s\n", (sap_addrtype?"IPv6":"IPv4")); |
88 | printf("Messagetype: %s\n", (sap_messagetype?"Announcement":"Deletion")); |
89 | printf("Encrypted: %d\n", sap_encrypted); |
90 | printf("Compressed: %d\n", sap_compressed); |
91 | printf("Authentication Length: %d\n", auth_len); |
92 | printf("Sender: %u\n", sender_address); |
93 | printf("Message Identifier Hash: %u\n", msgid); |
94 | #endif |
95 | |
96 | if (sap_addrtype) |
97 | continue; /* We don't support IPv6 for now */ |
98 | |
99 | #if 0 /* Getstream gets this wrong, see rfc2974 */ |
100 | if (sap_messagetype) |
101 | continue; /* We are not interested in deletions */ |
102 | #endif |
103 | |
104 | if (sap_encrypted || sap_compressed) |
105 | continue; |
b06a3250 |
106 | |
8447845f |
107 | /* RFC 2327 |
108 | * v=0 |
109 | * o=- 6dca 1 IN IP4 192.168.100.17:2000 |
110 | * s=TV Das Erste |
111 | * t=0 0 |
112 | * c=IN IP4 192.168.100.17/1 |
113 | * m=video 2000 http 33 |
114 | * a=tool:getstream |
115 | * a=type:broadcast |
116 | */ |
117 | |
118 | pos = payload; |
647c7747 |
119 | while(*pos != 0 && (pos-buffer) < recvd) { |
120 | if (*pos == 0x0d) |
8447845f |
121 | *pos = 0; |
8447845f |
122 | |
123 | if (*pos == 0x0a) { |
124 | *pos = 0; |
125 | |
126 | if (!strncasecmp("s=", payload, 2)) { |
127 | sname = payload + 2; |
128 | } else if (!strncasecmp("c=", payload, 2)) { |
129 | int poscnt = 0; |
130 | |
131 | payload += 2; |
132 | while (*payload != 0) { |
133 | if (poscnt == 2 && *payload == '/') { |
134 | *payload = 0; |
135 | break; |
136 | } |
137 | |
138 | if (*payload == ' ') { |
139 | *payload = 0; |
140 | poscnt++; |
141 | |
142 | /* c=<network type> <address type> <connection address> */ |
647c7747 |
143 | if (poscnt == 2) |
8447845f |
144 | host = payload + 1; |
8447845f |
145 | |
647c7747 |
146 | if (poscnt > 2) |
8447845f |
147 | break; |
8447845f |
148 | } |
149 | payload++; |
150 | } |
151 | } else if (!strncasecmp("m=", payload, 2)) { |
152 | int poscnt = 0; |
153 | |
154 | payload += 2; |
155 | while (*payload != 0) { |
156 | if (*payload == ' ') { |
157 | *payload = 0; |
158 | poscnt++; |
159 | |
160 | /* m=<media> <port> <transport> <fmt list> */ |
647c7747 |
161 | if (poscnt == 1) |
8447845f |
162 | port = payload + 1; |
8447845f |
163 | |
647c7747 |
164 | if (poscnt == 2) |
8447845f |
165 | proto = payload + 1; |
8447845f |
166 | |
647c7747 |
167 | if (poscnt > 2) |
8447845f |
168 | break; |
8447845f |
169 | } |
170 | payload++; |
171 | } |
172 | } |
173 | |
174 | payload = ++pos; |
175 | continue; |
176 | } |
177 | pos++; |
178 | } |
179 | |
180 | if (sname && proto && port) { |
181 | if (!host) { |
182 | struct in_addr inaddr; |
183 | |
184 | inaddr.s_addr = sender_address; |
185 | host = inet_ntoa(inaddr); |
186 | } |
187 | |
188 | #ifdef DEBUG |
189 | printf("%s -> %s://%s:%s\n", sname, proto, host, port); |
190 | #endif |
191 | |
192 | if (strlen(service) < strlen(sname)) { |
193 | sname += strlen(sname) - strlen(service); |
194 | } |
195 | |
196 | if (!strncasecmp(service, sname, strlen(service))) { |
197 | int len = strlen(host)+strlen(proto)+strlen(port)+5; |
198 | |
199 | if (!(url = malloc(len))) { |
200 | perror("malloc"); |
201 | return NULL; |
202 | } |
203 | |
204 | snprintf(url, len, "%s://%s:%s", proto, host, port); |
205 | url[len-1] = 0; |
206 | break; |
207 | } |
208 | } |
209 | |
210 | } while(curr.tv_sec < start.tv_sec+SAP_TIMEOUT); |
211 | |
212 | mreq.imr_multiaddr.s_addr = inet_addr(SAP_ADDR); |
213 | mreq.imr_interface.s_addr = INADDR_ANY; |
214 | setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); |
215 | |
90d8d87b |
216 | close(fd); |
217 | |
8447845f |
218 | return url; |
219 | } |