📄 sap.c
字号:
/*Copyright (C) 2006 Adam CharrettThis program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USAsap.cSession Announcement Protocol.*/#include "config.h"#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <string.h>#include <netdb.h>#include <pthread.h>#include "main.h"#include "logging.h"#include "list.h"#include "objects.h"#include "udp.h"#include "sap.h"/******************************************************************************** Defines ********************************************************************************/#define SAP_PORT (9875)/******************************************************************************** Typedefs ********************************************************************************/typedef struct SAPSession_s { bool deleted; uint16_t messageIdHash; struct sockaddr_storage originatingSource; char sdp[1000];}SAPSession_t;/******************************************************************************** Prototypes ********************************************************************************/static void SAPSessionFree(void *data);static int CreateSAPPacket(SAPSession_t *session, uint8_t *packet);static void DetermineSAPMulticast(SAPSession_t *session, struct sockaddr_storage *sockAddr);static void *SAPServer(void *arg);/******************************************************************************** Global variables ********************************************************************************/static const char mimeType[] = "application/sdp";static List_t *sessionList;static pthread_cond_t messageDelayCond = PTHREAD_COND_INITIALIZER;static pthread_mutex_t sessionListMutex = PTHREAD_MUTEX_INITIALIZER;static pthread_t serverThread;static uint16_t nextMessageIdHash = 1;static bool quit = FALSE;static char SAP[] = "SAP";/******************************************************************************** Global functions ********************************************************************************/bool IsMulticastAddress(struct sockaddr_storage *addr){ bool result = FALSE; if (addr->ss_family == PF_INET) { struct sockaddr_in *inAddr = (struct sockaddr_in *)addr; in_addr_t ip = ntohl(inAddr->sin_addr.s_addr); result = ((ip >= 0xe0000000) && (ip <= 0xefffffff)); LogModule(LOG_DEBUG, SAP, "ip=0x%08x result=%d\n", ip,result); } else {#ifndef __CYGWIN__ struct sockaddr_in6 *in6Addr = (struct sockaddr_in6*)addr; result = (in6Addr->sin6_addr.s6_addr[0] == 0xff);#endif } return result;}void SAPServerInit(void){ ObjectRegisterType(SAPSession_t); sessionList = ListCreate(); pthread_create(&serverThread, NULL, SAPServer, NULL);}void SAPServerDeinit(void){ quit = TRUE; pthread_cond_signal(&messageDelayCond); pthread_join(serverThread, NULL); ListFree(sessionList, SAPSessionFree);}SAPSessionHandle_t SAPServerAddSession(struct sockaddr_storage *originatingSource, char *sdp){ SAPSession_t *session; pthread_mutex_lock(&sessionListMutex); session = ObjectCreateType(SAPSession_t); if (session) { session->messageIdHash = nextMessageIdHash; nextMessageIdHash ++; memcpy(&session->originatingSource, originatingSource, sizeof(struct sockaddr_storage)); strcpy(session->sdp, sdp); ListAdd(sessionList, session); } pthread_mutex_unlock(&sessionListMutex); LogModule(LOG_DEBUG, SAP, "Added SAP session %x sdp:\n%s", session,sdp); return session;}void SAPServerDeleteSession(SAPSessionHandle_t handle){ SAPSession_t *session = handle; ListIterator_t iterator; pthread_mutex_lock(&sessionListMutex); ListRemove(sessionList, session); session->deleted = TRUE; ListIterator_Init(iterator, sessionList); ListInsertBeforeCurrent(&iterator, session); pthread_mutex_unlock(&sessionListMutex); LogModule(LOG_DEBUG, SAP, "Deleted SAP session %x\n", handle);}/******************************************************************************** Local Functions ********************************************************************************/static void SAPSessionFree(void *data){ ObjectRefDec(data);}static int CreateSAPPacket(SAPSession_t *session, uint8_t *packet){ int mimeTypeOffset = 0; /* Byte 0 : Version number V1 = 001 (3 bits) * Address type IPv4/IPv6 = 0/1 (1 bit) * Reserved 0 (1 bit) * Message Type ann/del = 0/1 (1 bit) * Encryption on/off = 0/1 (1 bit) * Compressed on/off = 0/1 (1 bit) */ packet[0] = 0x20 | (session->deleted ? 4:0); packet[1] = 0x00; /* Authentication length (not supported) */ packet[2] = session->messageIdHash & 0xff; packet[3] = (session->messageIdHash >> 8) & 0xff; if (session->originatingSource.ss_family == PF_INET) { struct sockaddr_in *inAddr =(struct sockaddr_in *)&session->originatingSource; mimeTypeOffset = 8; memcpy(&packet[4], &inAddr->sin_addr, 4); }#ifndef __CYGWIN__ else { struct sockaddr_in6 *in6Addr =(struct sockaddr_in6 *)&session->originatingSource; mimeTypeOffset = 20; memcpy(&packet[4], &in6Addr->sin6_addr, 16); }#endif memcpy(&packet[mimeTypeOffset], mimeType, sizeof(mimeType)); memcpy(&packet[mimeTypeOffset + sizeof(mimeType)], session->sdp, strlen(session->sdp)); return mimeTypeOffset + sizeof(mimeType) + strlen(session->sdp);}static void DetermineSAPMulticast(SAPSession_t *session, struct sockaddr_storage *sockAddr){ if (session->originatingSource.ss_family == PF_INET) { struct sockaddr_in *sessionAddr4 = (struct sockaddr_in*)&session->originatingSource; struct sockaddr_in *sockAddr4 = (struct sockaddr_in *)sockAddr; /* str is an IPv4 address */ in_addr_t ip = ntohl (sessionAddr4->sin_addr.s_addr); /* 224.0.0.0/24 => 224.0.0.255 */ if ((ip & 0xffffff00) == 0xe0000000) { ip = 0xe00000ff; } /* 239.255.0.0/16 => 239.255.255.255 */ else if ((ip & 0xffff0000) == 0xefff0000) { ip = 0xefffffff; } /* 239.192.0.0/14 => 239.195.255.255 */ else if ((ip & 0xfffc0000) == 0xefc00000) { ip = 0xefc3ffff; } /* other multicast address => 224.2.127.254 */ else { ip = 0xe0027ffe; } ip = htonl (ip); memset (sockAddr4, 0, sizeof (struct sockaddr_in)); sockAddr4->sin_family = AF_INET; sockAddr4->sin_port = htons (SAP_PORT); memcpy (&sockAddr4->sin_addr.s_addr, &ip, sizeof (ip)); }#ifndef __CYGWIN__ else { struct sockaddr_in6 *sessionAddr6 = (struct sockaddr_in6*)&session->originatingSource; struct sockaddr_in6 *sockAddr6 = (struct sockaddr_in6 *)sockAddr; memset (sockAddr6, 0, sizeof (struct sockaddr_in6)); sockAddr6->sin6_family = AF_INET6; sockAddr6->sin6_scope_id = sessionAddr6->sin6_scope_id; sockAddr6->sin6_port = htons (SAP_PORT); memcpy (&sockAddr6->sin6_addr.s6_addr, "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x7f\xfe", 16); sockAddr6->sin6_addr.s6_addr[1] = sessionAddr6->sin6_addr.s6_addr[1] & 0x0f; }#endif }static void *SAPServer(void *arg){ struct timespec waitFor; uint8_t packet[UDP_PAYLOAD_SIZE]; int packetLen; SAPSession_t *session; int sessionCount; ListIterator_t iterator; struct sockaddr_storage sapMulticastAddr; int socket4 = UDPCreateSocket(PF_INET);#ifndef __CYGWIN__ int socket6 = UDPCreateSocket(PF_INET6);#endif int ttl = 255; setsockopt(socket4,IPPROTO_IP,IP_MULTICAST_TTL, &ttl,sizeof(ttl));#ifndef __CYGWIN__ setsockopt(socket4,IPPROTO_IPV6,IPV6_MULTICAST_HOPS, &ttl,sizeof(ttl));#endif LogModule(LOG_DEBUG, SAP, "Annoucement thread starting\n"); while (!quit) { pthread_mutex_lock(&sessionListMutex); clock_gettime(CLOCK_REALTIME, &waitFor); sessionCount = ListCount(sessionList); if (sessionCount > 0) { /* Remove the first message from the front of the list, send it and * add it to the back. */ ListIterator_Init(iterator, sessionList); session = (SAPSession_t*)ListIterator_Current(iterator); ListRemoveCurrent(&iterator); if (session->deleted) { ObjectRefDec(session); } else { ListAdd(sessionList, session); } packetLen = CreateSAPPacket(session, packet); DetermineSAPMulticast(session, &sapMulticastAddr); /* Send the message */ if (session->originatingSource.ss_family == PF_INET) { UDPSendTo(socket4, packet, packetLen, (struct sockaddr *)&sapMulticastAddr, sizeof(struct sockaddr_in)); }#ifndef __CYGWIN__ else { UDPSendTo(socket6, packet, packetLen, (struct sockaddr *)&sapMulticastAddr, sizeof(struct sockaddr_in6)); }#endif } waitFor.tv_sec += 1; pthread_cond_timedwait(&messageDelayCond, &sessionListMutex, &waitFor); pthread_mutex_unlock(&sessionListMutex); } LogModule(LOG_DEBUG, SAP, "Annoucement thread finished.\n"); close(socket4); return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -