summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/sap.h169
1 files changed, 169 insertions, 0 deletions
diff --git a/tools/sap.h b/tools/sap.h
new file mode 100644
index 00000000..8bb2dae8
--- /dev/null
+++ b/tools/sap.h
@@ -0,0 +1,169 @@
+/*
+ * 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.1 2006-12-07 22:15:05 uid218003 Exp $
+ *
+ */
+
+#ifndef XINELIBOUTPUT_SAP_H_
+#define XINELIBOUTPUT_SAP_H_
+
+#include <arpa/inet.h>
+#include <endian.h>
+
+
+#define SAP_IP_ADDRESS "224.2.127.254" /* SAPv1 IP4 global scope multicast address */
+#define SAP_IP_TTL 255
+#define SAP_UDP_PORT 9875
+
+
+typedef struct {
+
+ /* RFC2974: SAP (Session Announcement Protocol) version 2 PDU */
+
+ union {
+ 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
+ };
+ uint8_t raw0;
+ };
+
+ uint8_t auth_len;
+ uint16_t msgid_hash;
+
+ union {
+ uint8_t u8[4];
+ uint32_t u32;
+ } ip4_source;
+
+ char payload[0];
+
+} __attribute__((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);
+
+ pdu = (sap_pdu_t*)malloc(length);
+
+ 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)
+{
+ /* zlib compression */
+
+ /* not implemented */
+
+ pdu->compressed = 0;
+ return -1;
+}
+
+static inline int sap_send_pdu(sap_pdu_t *pdu, uint32_t dst_ip)
+{
+ int len = 0, r;
+ int iReuse = 1, iLoop = 1, iTtl = SAP_IP_TTL;
+ int 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);
+
+ 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);
+
+ // 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 0
+ /* log PDU */
+ for(int i=0; i<len;) {
+ char x[4096]="", a[4096]="";
+ for(int j=0; j<16 && i<len; i++, j++) {
+ char t[8], ch = ((char*)pdu)[i];
+ sprintf(t, "%02X ", ((unsigned int)ch)&0xff);
+ strcat(x, t);
+ sprintf(t, "%c", (ch>=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_ */