X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/record-dvb/blobdiff_plain/647c7747f9b9c0776fd4e12ef55d11e24b3495cb..HEAD:/sap.c diff --git a/sap.c b/sap.c index 232c0c3..da1d959 100644 --- a/sap.c +++ b/sap.c @@ -22,11 +22,103 @@ #define BUFFSIZE SAP_MAX_SIZE +struct sdp_info { + char *service; + char *host; + char *proto; + char *port; +}; + +struct sdp_info *parse_sdp(char *sdp, int len) +{ + char *pos, *line; + static struct sdp_info sdpinfo; + + /* 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 + */ + + bzero(&sdpinfo, sizeof(struct sdp_info)); + + pos = line = sdp; + while(*pos != 0 && (pos-sdp) < len) { + if (*pos == 0x0d) + *pos = 0; + + if (*pos == 0x0a) { + *pos = 0; + + if (!strncasecmp("s=", line, 2)) { + sdpinfo.service = line + 2; + } else if (!strncasecmp("c=", line, 2)) { + int poscnt = 0; + + line += 2; + while (*line != 0) { + if (poscnt == 2 && *line == '/') { + *line = 0; + break; + } + + if (*line == ' ') { + *line = 0; + poscnt++; + + /* c=
*/ + if (poscnt == 2) + sdpinfo.host = line + 1; + + if (poscnt > 2) + break; + } + line++; + } + } else if (!strncasecmp("m=", line, 2)) { + int poscnt = 0; + + line += 2; + while (*line != 0) { + if (*line == ' ') { + *line = 0; + poscnt++; + + /* m= */ + if (poscnt == 1) + sdpinfo.port = line + 1; + + if (poscnt == 2) + sdpinfo.proto = line + 1; + + if (poscnt > 2) + break; + } + line++; + } + } + + line = ++pos; + continue; + } + pos++; + } + + return &sdpinfo; +} + + char *get_url_from_sap(char *service) { struct timeval start, curr; struct ip_mreq mreq; unsigned char buffer[BUFFSIZE]; + struct in_addr sapinaddr; char *url = NULL; int fd; @@ -38,14 +130,15 @@ char *get_url_from_sap(char *service) 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; fd_set rfds; struct timeval tv; int retval; + int sap_version, sap_addrtype, sap_messagetype, sap_encrypted, sap_compressed; + uint8_t sender_address[16]; /* This might be IPv6! */ + unsigned char auth_len; + unsigned short msgid; + unsigned char *sdp; + struct sdp_info *sdpinfo; FD_ZERO(&rfds); FD_SET(fd, &rfds); @@ -55,7 +148,7 @@ char *get_url_from_sap(char *service) if ((retval = select(fd+1, &rfds, NULL, NULL, &tv)) == -1) { perror("select"); - return NULL; + break; } if (!retval) { @@ -63,9 +156,10 @@ char *get_url_from_sap(char *service) continue; } + bzero(buffer, BUFFSIZE); if ((recvd = recv(fd, buffer, BUFFSIZE, 0)) < 1) { perror("recv"); - return NULL; + break; } gettimeofday(&curr, NULL); @@ -77,8 +171,8 @@ char *get_url_from_sap(char *service) 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; + memcpy(sender_address, buffer+4, (sap_addrtype?16:4)); + sdp = buffer + 4 /* (sap_*, auth_len, msgid) */ + (sap_addrtype?16:4) + auth_len; #ifdef DEBUG printf("\n"); @@ -88,13 +182,10 @@ char *get_url_from_sap(char *service) 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("Sender: %u\n", *((in_addr_t*)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 */ @@ -103,112 +194,62 @@ char *get_url_from_sap(char *service) 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) < recvd) { - 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; - } + sdpinfo = parse_sdp(sdp, recvd-(sdp-buffer)); - if (*payload == ' ') { - *payload = 0; - poscnt++; + if (sdpinfo->service && sdpinfo->proto && sdpinfo->port) { + char hostbuf[INET6_ADDRSTRLEN]; - /* c=
*/ - if (poscnt == 2) - host = payload + 1; + if (!sdpinfo->host) { - 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++; - } - } + if (sap_addrtype) { + struct in6_addr in6addr; - payload = ++pos; - continue; - } - pos++; - } + memcpy(in6addr.s6_addr, sender_address, 16); + if (!(sdpinfo->host = (char*)inet_ntop(AF_INET6, &in6addr, hostbuf, INET6_ADDRSTRLEN))) { + perror("inet_ntop"); + continue; + } + } else { + struct in_addr inaddr; - if (sname && proto && port) { - if (!host) { - struct in_addr inaddr; - - inaddr.s_addr = sender_address; - host = inet_ntoa(inaddr); + inaddr.s_addr = *((in_addr_t*)sender_address); + if (!(sdpinfo->host = (char*)inet_ntop(AF_INET, &inaddr, hostbuf, INET6_ADDRSTRLEN))) { + perror("inet_ntop"); + continue; + } + } } #ifdef DEBUG - printf("%s -> %s://%s:%s\n", sname, proto, host, port); + printf("%s -> %s://%s:%s\n", sdpinfo->service, sdpinfo->proto, sdpinfo->host, sdpinfo->port); #endif - if (strlen(service) < strlen(sname)) { - sname += strlen(sname) - strlen(service); + if (strlen(service) < strlen(sdpinfo->service)) { + sdpinfo->service += strlen(sdpinfo->service) - strlen(service); } - if (!strncasecmp(service, sname, strlen(service))) { - int len = strlen(host)+strlen(proto)+strlen(port)+5; + if (!strncasecmp(service, sdpinfo->service, strlen(service))) { + int len = strlen(sdpinfo->host)+strlen(sdpinfo->proto)+strlen(sdpinfo->port)+5; if (!(url = malloc(len))) { perror("malloc"); - return NULL; + break; } - snprintf(url, len, "%s://%s:%s", proto, host, port); + snprintf(url, len, "%s://%s:%s", sdpinfo->proto, sdpinfo->host, sdpinfo->port); url[len-1] = 0; break; } } - } while(curr.tv_sec < start.tv_sec+SAP_TIMEOUT); + } while(curr.tv_sec < start.tv_sec+SAP_TIMEOUT || + ((curr.tv_sec == start.tv_sec+SAP_TIMEOUT) && (curr.tv_usec < start.tv_usec))); + + if (!(inet_aton(SAP_ADDR, &sapinaddr))) { + perror("inet_aton"); + } - mreq.imr_multiaddr.s_addr = inet_addr(SAP_ADDR); + mreq.imr_multiaddr.s_addr = sapinaddr.s_addr; mreq.imr_interface.s_addr = INADDR_ANY; setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));