static void ssdp_shutdown(void *opaque, int retcode) { // Prevent SSDP from announcing any more, not waterproof but should work ssdp_run = 0; ssdp_send_notify("ssdp:byebye"); }
static void * ssdp_thread(void *aux) { struct sockaddr_in si = {0}; int fdm, fdu; int one = 1, r; int64_t next_send = 0; struct pollfd fds[2]; socklen_t sl = sizeof(struct sockaddr_in); struct ip_mreq imr; fdm = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(fdm, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); #if defined(SO_REUSEPORT) setsockopt(fdm, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(int)); #endif #if defined(IP_RECVDSTADDR) setsockopt(fdm, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(int)); #endif si.sin_family = AF_INET; si.sin_port = htons(1900); if(bind(fdm, (struct sockaddr *)&si, sizeof(struct sockaddr_in)) == -1) { TRACE(TRACE_ERROR, "SSDP", "Unable to bind -- %s", strerror(errno)); return NULL; } memset(&imr, 0, sizeof(imr)); imr.imr_multiaddr.s_addr = htonl(0xeffffffa); // 239.255.255.250 if(setsockopt(fdm, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) == -1) { TRACE(TRACE_ERROR, "SSDP", "Unable to join 239.255.255.250: %s", strerror(errno)); return NULL; } fdu = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #if defined(IP_RECVDSTADDR) setsockopt(fdu, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(int)); #endif si.sin_family = AF_INET; si.sin_port = 0; if(bind(fdu, (struct sockaddr *)&si, sizeof(struct sockaddr_in)) == -1) { TRACE(TRACE_ERROR, "SSDP", "Unable to bind"); return NULL; } if(getsockname(fdu, (struct sockaddr *)&ssdp_selfaddr, &sl) == -1) { TRACE(TRACE_ERROR, "SSDP", "Unable to figure local port"); return NULL; } ssdp_fdm = fdm; ssdp_fdu = fdu; ssdp_send_static(fdu, SEARCHREQ); fds[0].fd = fdm; fds[0].events = POLLIN; fds[1].fd = fdu; fds[1].events = POLLIN; while(ssdp_run) { int64_t delta = next_send - showtime_get_ts(); if(delta <= 0) { delta = 15000000LL; next_send = showtime_get_ts() + delta; ssdp_send_notify("ssdp:alive"); } r = poll(fds, 2, (delta / 1000) + 1); if(r > 0 && fds[0].revents & POLLIN) ssdp_input(fdm, 1); if(r > 0 && fds[1].revents & POLLIN) ssdp_input(fdu, 0); } return NULL; }
static int ssdp_loop(int log_fail) { struct sockaddr_in si = {0}; int fdm, fdu; int one = 1, r; int64_t next_send = 0; struct pollfd fds[2]; struct ip_mreq imr; fdm = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(fdm, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); #if defined(SO_REUSEPORT) setsockopt(fdm, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(int)); #endif #if defined(IP_RECVDSTADDR) setsockopt(fdm, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(int)); #endif si.sin_family = AF_INET; si.sin_port = htons(1900); if(bind(fdm, (struct sockaddr *)&si, sizeof(struct sockaddr_in)) == -1) { if(log_fail) TRACE(TRACE_ERROR, "SSDP", "Unable to bind -- %s", strerror(errno)); close(fdm); return 1; } memset(&imr, 0, sizeof(imr)); imr.imr_multiaddr.s_addr = htonl(0xeffffffa); // 239.255.255.250 if(setsockopt(fdm, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) == -1) { if(log_fail) TRACE(TRACE_ERROR, "SSDP", "Unable to join 239.255.255.250: %s", strerror(errno)); close(fdm); return 1; } fdu = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #if defined(IP_RECVDSTADDR) setsockopt(fdu, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(int)); #endif si.sin_family = AF_INET; si.sin_port = 0; if(bind(fdu, (struct sockaddr *)&si, sizeof(struct sockaddr_in)) == -1) { if(log_fail) TRACE(TRACE_ERROR, "SSDP", "Unable to bind -- %s", strerror(errno)); close(fdu); close(fdm); return 1; } ssdp_fdm = fdm; ssdp_fdu = fdu; ssdp_send_static(fdu, SEARCHREQ); fds[0].fd = fdm; fds[0].events = POLLIN; fds[1].fd = fdu; fds[1].events = POLLIN; TRACE(TRACE_DEBUG, "SSDP", "Running"); while(ssdp_run) { int64_t delta = next_send - arch_get_ts(); if(delta <= 0) { delta = 15000000LL; next_send = arch_get_ts() + delta; ssdp_send_notify("ssdp:alive"); } r = poll(fds, 2, (delta / 1000) + 1); if(r > 0 && fds[0].revents & POLLIN) ssdp_input(fdm, 1); if(r > 0 && fds[1].revents & POLLIN) ssdp_input(fdu, 0); } return 0; }