From: michael Date: Sun, 2 Jul 2006 00:32:46 +0000 (+0000) Subject: add SAP/SDP support X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/record-dvb/commitdiff_plain/8447845ff6a909797551483cab14a24e5bcf7888 add SAP/SDP support --- diff --git a/Makefile b/Makefile index e0ba4f3..ad5e035 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS =-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -Wall -g -COMMONOBJS = http.o mcast.o common.o +COMMONOBJS = http.o mcast.o sap.o common.o OBJS = record-dvb.o dump-mcast.o $(COMMONOBJS) all: record-dvb dump-mcast diff --git a/record-dvb.c b/record-dvb.c index bb69447..d87d3e7 100644 --- a/record-dvb.c +++ b/record-dvb.c @@ -12,6 +12,7 @@ #include "http.h" #include "mcast.h" +#include "sap.h" #define CHUNKSIZE 3000 #define GTOD_INTERVAL 100 @@ -97,12 +98,20 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + if (!is_http(url) && !is_mcast(url)) { + char *service_url; + if ((service_url = get_url_from_sap(url))) { + printf("SAP says: '%s' -> %s\n", url, service_url); + url = service_url; + } + } + if (is_http(url)) { open_fn = &open_http; } else if (is_mcast(url)) { open_fn = &open_mcast; } else { - printf("URL %s not supported!\n", url); + printf("URL '%s' not supported!\n", url); exit(EXIT_FAILURE); } diff --git a/sap.c b/sap.c new file mode 100644 index 0000000..8dfa694 --- /dev/null +++ b/sap.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcast.h" +#include "sap.h" + +#define SAP_ADDR "224.2.127.254" +#define SAP_PORT 9875 +#define SAP_MAX_SIZE 1024 + +#define SAP_TIMEOUT 3 + +#define BUFFSIZE SAP_MAX_SIZE + +char *get_url_from_sap(char *service) +{ + struct timeval start, curr; + struct ip_mreq mreq; + unsigned char buffer[BUFFSIZE]; + char *url = NULL; + int fd; + + snprintf(buffer,BUFFSIZE,"udp://%s:%u", SAP_ADDR, SAP_PORT); + + fd = open_mcast(buffer); + + gettimeofday(&start, NULL); + + do { + int recvd; + int sap_version, sap_addrtype, sap_messagetype, sap_encrypted, sap_compressed; + in_addr_t sender_address; + unsigned char auth_len; + unsigned short msgid; + unsigned char *payload, *pos, *host = NULL, *proto = NULL, *port = NULL, *sname = NULL; + + if ((recvd = recv(fd, buffer, BUFFSIZE, 0)) < 1) { + perror("recv"); + return NULL; + } + + gettimeofday(&curr, NULL); + + sap_version = (buffer[0] >> 5) & 0x7; + sap_addrtype = (buffer[0] >> 4) & 0x1; + sap_messagetype = (buffer[0] >> 2) & 0x1; + sap_encrypted = (buffer[0] >> 1) & 0x1; + sap_compressed = buffer[0] & 0x1; + auth_len = buffer[1]; + msgid = buffer[2] << 8 | buffer[3]; + memcpy(&sender_address, buffer+4, (sap_addrtype?16:4)); + payload = buffer + 4 /* (sap_*, auth_len, msgid) */ + (sap_addrtype?16:4) + auth_len; + +#ifdef DEBUG + printf("\n"); + printf("SAP-Version: %d\n", sap_version); + printf("Adresstyp: %s\n", (sap_addrtype?"IPv6":"IPv4")); + printf("Messagetype: %s\n", (sap_messagetype?"Announcement":"Deletion")); + printf("Encrypted: %d\n", sap_encrypted); + printf("Compressed: %d\n", sap_compressed); + printf("Authentication Length: %d\n", auth_len); + printf("Sender: %u\n", sender_address); + printf("Message Identifier Hash: %u\n", msgid); +#endif + + if (sap_addrtype) + continue; /* We don't support IPv6 for now */ + +#if 0 /* Getstream gets this wrong, see rfc2974 */ + if (sap_messagetype) + continue; /* We are not interested in deletions */ +#endif + + if (sap_encrypted || sap_compressed) + continue; + /* RFC 2327 + * v=0 + * o=- 6dca 1 IN IP4 192.168.100.17:2000 + * s=TV Das Erste + * t=0 0 + * c=IN IP4 192.168.100.17/1 + * m=video 2000 http 33 + * a=tool:getstream + * a=type:broadcast + */ + + pos = payload; + while(*pos != 0 && (pos-buffer) < BUFFSIZE) { + if (*pos == 0x0d) { + *pos = 0; + } + + if (*pos == 0x0a) { + *pos = 0; + + if (!strncasecmp("s=", payload, 2)) { + sname = payload + 2; + } else if (!strncasecmp("c=", payload, 2)) { + int poscnt = 0; + + payload += 2; + while (*payload != 0) { + if (poscnt == 2 && *payload == '/') { + *payload = 0; + break; + } + + if (*payload == ' ') { + *payload = 0; + poscnt++; + + /* c=
*/ + if (poscnt == 2) { + host = payload + 1; + } + + if (poscnt > 2) { + break; + } + } + payload++; + } + } else if (!strncasecmp("m=", payload, 2)) { + int poscnt = 0; + + payload += 2; + while (*payload != 0) { + if (*payload == ' ') { + *payload = 0; + poscnt++; + + /* m= */ + if (poscnt == 1) { + port = payload + 1; + } + + if (poscnt == 2) { + proto = payload + 1; + } + + if (poscnt > 2) { + break; + } + } + payload++; + } + } + + payload = ++pos; + continue; + } + pos++; + } + + if (sname && proto && port) { + if (!host) { + struct in_addr inaddr; + + inaddr.s_addr = sender_address; + host = inet_ntoa(inaddr); + } + +#ifdef DEBUG + printf("%s -> %s://%s:%s\n", sname, proto, host, port); +#endif + + if (strlen(service) < strlen(sname)) { + sname += strlen(sname) - strlen(service); + } + + if (!strncasecmp(service, sname, strlen(service))) { + int len = strlen(host)+strlen(proto)+strlen(port)+5; + + if (!(url = malloc(len))) { + perror("malloc"); + return NULL; + } + + snprintf(url, len, "%s://%s:%s", proto, host, port); + url[len-1] = 0; + break; + } + } + + } while(curr.tv_sec < start.tv_sec+SAP_TIMEOUT); + + mreq.imr_multiaddr.s_addr = inet_addr(SAP_ADDR); + mreq.imr_interface.s_addr = INADDR_ANY; + setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); + + return url; +} diff --git a/sap.h b/sap.h new file mode 100644 index 0000000..8bc599f --- /dev/null +++ b/sap.h @@ -0,0 +1 @@ +char *get_url_from_sap(char *service);