/* * sap.h: RFC2974 Session Announcement Protocol (SAP) version 2 * * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * * $Id: sap.h,v 1.8 2007-03-29 14:22:30 phintuka Exp $ * */ #ifndef XINELIBOUTPUT_SAP_H_ #define XINELIBOUTPUT_SAP_H_ #include #ifdef __APPLE__ # include #else # include #endif #ifndef PACKED # define PACKED __attribute__((packed)) #endif /*#define LOG_SAP*/ /* SAP IPv4 multicast addresses */ #define SAP_IP_ADDRESS_GLOBAL "224.2.127.254" /* SAPv1 IP4 global scope multicast address */ #define SAP_IP_ADDRESS_ORG "239.195.255.255" /* organization-local */ #define SAP_IP_ADDRESS_LOCAL "239.255.255.255" /* local */ #define SAP_IP_ADDRESS_LINK "224.0.0.255" /* link-local */ #define SAP_IP_TTL 255 #define SAP_UDP_PORT 9875 typedef struct { /* RFC2974: SAP (Session Announcement Protocol) version 2 PDU */ union { uint8_t raw0; struct { #if __BYTE_ORDER == __BIG_ENDIAN uint8_t version : 3; uint8_t addr_type : 1; uint8_t reserved : 1; uint8_t msg_type : 1; uint8_t encrypted : 1; uint8_t compressed : 1; #else uint8_t compressed : 1; uint8_t encrypted : 1; uint8_t msg_type : 1; uint8_t reserved : 1; uint8_t addr_type : 1; uint8_t version : 3; #endif } PACKED; } PACKED; uint8_t auth_len; uint16_t msgid_hash; union { uint8_t u8[4]; uint32_t u32; } PACKED ip4_source; char payload[0]; } PACKED sap_pdu_t; static inline sap_pdu_t *sap_create_pdu(uint32_t src_ip, uint16_t msgid, int announce, const char *payload_type, const char *payload) { sap_pdu_t *pdu; int length = sizeof(sap_pdu_t) + strlen(payload) + 3; if(payload_type) length += strlen(payload_type); if(! (pdu = (sap_pdu_t*)malloc(length))) return NULL; memset(pdu, 0, sizeof(sap_pdu_t)); pdu->version = 1; /* SAP v1 / v2 */ pdu->msg_type = announce ? 0 : 1; pdu->msgid_hash = msgid; pdu->ip4_source.u32 = src_ip; if(payload_type) { char *tmp = &pdu->payload[0]; strcpy(tmp, payload_type); tmp += strlen(tmp) + 1; strcpy(tmp, payload); } else { /* payload type defaults to application/sdp */ sprintf(&pdu->payload[0], "%s%c%c", payload, 0, 0); } return pdu; } static inline int sap_compress_pdu(sap_pdu_t *pdu) { #ifdef HAVE_ZLIB_H /* zlib compression */ Compress(); /*pdu->compressed = 1;*/ #endif /* not implemented */ pdu->compressed = 0; return -1; } static inline int sap_send_pdu(int *pfd, sap_pdu_t *pdu, uint32_t dst_ip) { int len = 0, r; int iReuse = 1, iLoop = 1, iTtl = SAP_IP_TTL; int fd; if(!pfd || *pfd < 0) { fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd < 0) { LOGERR("socket() failed (UDP/SAP multicast)"); return -1; } setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &iReuse, sizeof(int)); setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &iTtl, sizeof(int)); setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &iLoop, sizeof(int)); // Connect to multicast address struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(SAP_UDP_PORT); sin.sin_addr.s_addr = dst_ip ? dst_ip : inet_addr(SAP_IP_ADDRESS_GLOBAL); if(connect(fd, (struct sockaddr *)&sin, sizeof(sin))==-1) LOGERR("UDP/SAP multicast connect() failed."); // Set to non-blocking mode fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK); if(pfd) *pfd = fd; } else { fd = *pfd; } // size of PDU len += strlen(&pdu->payload[0]); if(!strstr(&pdu->payload[0], "\r\n")) { /* assume mime content type is present */ len += 1; len += strlen(&pdu->payload[len]); len += sizeof(sap_pdu_t); } // network order pdu->msgid_hash = htons(pdu->msgid_hash); // send r = send(fd, pdu, len, 0); if(r < 0) LOGERR("UDP/SAP multicast send() failed."); if(!pfd) close(fd); #ifdef LOG_SAP /* log PDU */ for(int i=0; i=32 && ch<127) ? ch : '.'); strcat(a, t); } LOGMSG("SAP: 0x%02x: %-50s%-18s", i/16-1, x, a); } #endif // back to host order pdu->msgid_hash = ntohs(pdu->msgid_hash); return r == len ? len : -1; } #endif /* XINELIBOUTPUT_SAP_H_ */