/* * Discovery thread */ static void * upnp_thread( void *aux ) { char *bindaddr = aux; tvhpoll_t *poll = tvhpoll_create(2); tvhpoll_event_t ev[2]; upnp_data_t *data; udp_connection_t *multicast = NULL, *unicast = NULL; udp_connection_t *conn; unsigned char buf[16384]; upnp_service_t *us; struct sockaddr_storage ip; socklen_t iplen; size_t size; int r, delay_ms; multicast = udp_bind(LS_UPNP, "upnp_thread_multicast", "239.255.255.250", 1900, NULL, NULL, 32*1024, 32*1024); if (multicast == NULL || multicast == UDP_FATAL_ERROR) goto error; unicast = udp_bind(LS_UPNP, "upnp_thread_unicast", bindaddr, 0, NULL, NULL, 32*1024, 32*1024); if (unicast == NULL || unicast == UDP_FATAL_ERROR) goto error; memset(&ev, 0, sizeof(ev)); ev[0].fd = multicast->fd; ev[0].events = TVHPOLL_IN; ev[0].ptr = multicast; ev[1].fd = unicast->fd; ev[1].events = TVHPOLL_IN; ev[1].ptr = unicast; tvhpoll_add(poll, ev, 2); delay_ms = 0; while (atomic_get(&upnp_running) && multicast->fd >= 0) { r = tvhpoll_wait(poll, ev, 2, delay_ms ?: 1000); if (r == 0) /* timeout */ delay_ms = 0; while (r-- > 0) { if ((ev[r].events & TVHPOLL_IN) != 0) { conn = ev[r].ptr; iplen = sizeof(ip); size = recvfrom(conn->fd, buf, sizeof(buf), 0, (struct sockaddr *)&ip, &iplen); if (size > 0 && tvhtrace_enabled()) { char tbuf[256]; inet_ntop(ip.ss_family, IP_IN_ADDR(ip), tbuf, sizeof(tbuf)); tvhtrace(LS_UPNP, "%s - received data from %s:%hu [size=%zi]", conn == multicast ? "multicast" : "unicast", tbuf, (unsigned short) ntohs(IP_PORT(ip)), size); tvhlog_hexdump(LS_UPNP, buf, size); } /* TODO: a filter */ TAILQ_FOREACH(us, &upnp_services, us_link) us->us_received(buf, size, conn, &ip); } } while (delay_ms == 0) { tvh_mutex_lock(&upnp_lock); data = TAILQ_FIRST(&upnp_data_write); if (data) { delay_ms = data->delay_ms; data->delay_ms = 0; if (!delay_ms) { TAILQ_REMOVE(&upnp_data_write, data, data_link); } else { data = NULL; } } tvh_mutex_unlock(&upnp_lock); if (data == NULL) break; upnp_dump_data(data); udp_write_queue(data->from_multicast ? multicast : unicast, &data->queue, &data->storage); htsbuf_queue_flush(&data->queue); free(data); delay_ms = 0; } } /* flush the write queue (byebye messages) */ while (1) { tvh_mutex_lock(&upnp_lock); data = TAILQ_FIRST(&upnp_data_write); if (data) TAILQ_REMOVE(&upnp_data_write, data, data_link); tvh_mutex_unlock(&upnp_lock); if (data == NULL) break; tvh_safe_usleep((long)data->delay_ms * 1000); upnp_dump_data(data); udp_write_queue(unicast, &data->queue, &data->storage); htsbuf_queue_flush(&data->queue); free(data); } error: atomic_set(&upnp_running, 0); tvhpoll_destroy(poll); udp_close(unicast); udp_close(multicast); return NULL; }
/* * Discovery thread */ static void * upnp_thread( void *aux ) { char *bindaddr = aux; tvhpoll_t *poll = tvhpoll_create(2); tvhpoll_event_t ev[2]; upnp_data_t *data; udp_connection_t *multicast = NULL, *unicast = NULL; udp_connection_t *conn; unsigned char buf[16384]; upnp_service_t *us; struct sockaddr_storage ip; socklen_t iplen; size_t size; int r; multicast = udp_bind("upnp", "upnp_thread_multicast", "239.255.255.250", 1900, NULL, 32*1024); if (multicast == NULL || multicast == UDP_FATAL_ERROR) goto error; unicast = udp_bind("upnp", "upnp_thread_unicast", bindaddr, 0, NULL, 32*1024); if (unicast == NULL || unicast == UDP_FATAL_ERROR) goto error; memset(&ev, 0, sizeof(ev)); ev[0].fd = multicast->fd; ev[0].events = TVHPOLL_IN; ev[0].data.ptr = multicast; ev[1].fd = unicast->fd; ev[1].events = TVHPOLL_IN; ev[1].data.ptr = unicast; tvhpoll_add(poll, ev, 2); while (upnp_running && multicast->fd >= 0) { r = tvhpoll_wait(poll, ev, 2, 1000); while (r-- > 0) { if ((ev[r].events & TVHPOLL_IN) != 0) { conn = ev[r].data.ptr; iplen = sizeof(ip); size = recvfrom(conn->fd, buf, sizeof(buf), 0, (struct sockaddr *)&ip, &iplen); #if ENABLE_TRACE if (size > 0) { char tbuf[256]; inet_ntop(ip.ss_family, IP_IN_ADDR(ip), tbuf, sizeof(tbuf)); tvhtrace("upnp", "%s - received data from %s:%hu [size=%zi]", conn == multicast ? "multicast" : "unicast", tbuf, (unsigned short) IP_PORT(ip), size); tvhlog_hexdump("upnp", buf, size); } #endif /* TODO: a filter */ TAILQ_FOREACH(us, &upnp_services, us_link) us->us_received(buf, size, conn, &ip); } } while (1) { pthread_mutex_lock(&upnp_lock); data = TAILQ_FIRST(&upnp_data_write); if (data) TAILQ_REMOVE(&upnp_data_write, data, data_link); pthread_mutex_unlock(&upnp_lock); if (data == NULL) break; udp_write_queue(unicast, &data->queue, &data->storage); htsbuf_queue_flush(&data->queue); free(data); } } error: upnp_running = 0; tvhpoll_destroy(poll); udp_close(unicast); udp_close(multicast); return NULL; }