]> git.zerfleddert.de Git - record-dvb/blob - sap.c
64f1437b5eab519b3b80d565d6d4f5376677b0cb
[record-dvb] / sap.c
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 bzero(buffer, BUFFSIZE);
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;
106
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;
119 while(*pos != 0 && (pos-buffer) < recvd) {
120 if (*pos == 0x0d)
121 *pos = 0;
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> */
143 if (poscnt == 2)
144 host = payload + 1;
145
146 if (poscnt > 2)
147 break;
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> */
161 if (poscnt == 1)
162 port = payload + 1;
163
164 if (poscnt == 2)
165 proto = payload + 1;
166
167 if (poscnt > 2)
168 break;
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
216 close(fd);
217
218 return url;
219 }
Impressum, Datenschutz