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