1 /*
2 * tvheadend, UPnP interface
3 * Copyright (C) 2014 Jaroslav Kysela
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <pthread.h>
20 #include <assert.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <signal.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <arpa/inet.h>
32
33 #include "tvheadend.h"
34 #include "tvhpoll.h"
35 #include "upnp.h"
36
37 #if defined(PLATFORM_FREEBSD) || ENABLE_ANDROID
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #endif
41
42 int upnp_running;
43 static pthread_t upnp_tid;
44 pthread_mutex_t upnp_lock;
45
46 TAILQ_HEAD(upnp_active_services, upnp_service);
47
48 typedef struct upnp_data {
49 TAILQ_ENTRY(upnp_data) data_link;
50 struct sockaddr_storage storage;
51 htsbuf_queue_t queue;
52 int delay_ms;
53 int from_multicast;
54 } upnp_data_t;
55
56 TAILQ_HEAD(upnp_data_queue_write, upnp_data);
57
58 static struct upnp_active_services upnp_services;
59 static struct upnp_data_queue_write upnp_data_write;
60 static struct sockaddr_storage upnp_ipv4_multicast;
61
62 /*
63 *
64 */
upnp_service_create0(upnp_service_t * us)65 upnp_service_t *upnp_service_create0( upnp_service_t *us )
66 {
67 pthread_mutex_lock(&upnp_lock);
68 TAILQ_INSERT_TAIL(&upnp_services, us, us_link);
69 pthread_mutex_unlock(&upnp_lock);
70 return us;
71 }
72
upnp_service_destroy(upnp_service_t * us)73 void upnp_service_destroy( upnp_service_t *us )
74 {
75 pthread_mutex_lock(&upnp_lock);
76 TAILQ_REMOVE(&upnp_services, us, us_link);
77 us->us_destroy(us);
78 pthread_mutex_unlock(&upnp_lock);
79 free(us);
80 }
81
82 /*
83 *
84 */
85 void
upnp_send(htsbuf_queue_t * q,struct sockaddr_storage * storage,int delay_ms,int from_multicast)86 upnp_send( htsbuf_queue_t *q, struct sockaddr_storage *storage,
87 int delay_ms, int from_multicast )
88 {
89 upnp_data_t *data;
90
91 if (!atomic_get(&upnp_running))
92 return;
93 data = calloc(1, sizeof(upnp_data_t));
94 htsbuf_queue_init(&data->queue, 0);
95 htsbuf_appendq(&data->queue, q);
96 if (storage == NULL)
97 data->storage = upnp_ipv4_multicast;
98 else
99 data->storage = *storage;
100 data->delay_ms = delay_ms;
101 data->from_multicast = from_multicast;
102 pthread_mutex_lock(&upnp_lock);
103 TAILQ_INSERT_TAIL(&upnp_data_write, data, data_link);
104 pthread_mutex_unlock(&upnp_lock);
105 }
106
107 /*
108 *
109 */
110 static void
upnp_dump_data(upnp_data_t * data)111 upnp_dump_data( upnp_data_t *data )
112 {
113 #if 0
114 char tbuf[256];
115 inet_ntop(data->storage.ss_family, IP_IN_ADDR(data->storage), tbuf, sizeof(tbuf));
116 printf("upnp out to %s:%d\n", tbuf, ntohs(IP_PORT(data->storage)));
117 htsbuf_hexdump(&data->queue, "upnp out");
118 #endif
119 }
120
121 /*
122 * Discovery thread
123 */
124 static void *
upnp_thread(void * aux)125 upnp_thread( void *aux )
126 {
127 char *bindaddr = aux;
128 tvhpoll_t *poll = tvhpoll_create(2);
129 tvhpoll_event_t ev[2];
130 upnp_data_t *data;
131 udp_connection_t *multicast = NULL, *unicast = NULL;
132 udp_connection_t *conn;
133 unsigned char buf[16384];
134 upnp_service_t *us;
135 struct sockaddr_storage ip;
136 socklen_t iplen;
137 size_t size;
138 int r, delay_ms;
139
140 multicast = udp_bind(LS_UPNP, "upnp_thread_multicast",
141 "239.255.255.250", 1900, NULL,
142 NULL, 32*1024, 32*1024);
143 if (multicast == NULL || multicast == UDP_FATAL_ERROR)
144 goto error;
145 unicast = udp_bind(LS_UPNP, "upnp_thread_unicast", bindaddr, 0, NULL,
146 NULL, 32*1024, 32*1024);
147 if (unicast == NULL || unicast == UDP_FATAL_ERROR)
148 goto error;
149
150 memset(&ev, 0, sizeof(ev));
151 ev[0].fd = multicast->fd;
152 ev[0].events = TVHPOLL_IN;
153 ev[0].data.ptr = multicast;
154 ev[1].fd = unicast->fd;
155 ev[1].events = TVHPOLL_IN;
156 ev[1].data.ptr = unicast;
157 tvhpoll_add(poll, ev, 2);
158
159 delay_ms = 0;
160
161 while (atomic_get(&upnp_running) && multicast->fd >= 0) {
162 r = tvhpoll_wait(poll, ev, 2, delay_ms ?: 1000);
163 if (r == 0) /* timeout */
164 delay_ms = 0;
165
166 while (r-- > 0) {
167 if ((ev[r].events & TVHPOLL_IN) != 0) {
168 conn = ev[r].data.ptr;
169 iplen = sizeof(ip);
170 size = recvfrom(conn->fd, buf, sizeof(buf), 0,
171 (struct sockaddr *)&ip, &iplen);
172 if (size > 0 && tvhtrace_enabled()) {
173 char tbuf[256];
174 inet_ntop(ip.ss_family, IP_IN_ADDR(ip), tbuf, sizeof(tbuf));
175 tvhtrace(LS_UPNP, "%s - received data from %s:%hu [size=%zi]",
176 conn == multicast ? "multicast" : "unicast",
177 tbuf, (unsigned short) ntohs(IP_PORT(ip)), size);
178 tvhlog_hexdump(LS_UPNP, buf, size);
179 }
180 /* TODO: a filter */
181 TAILQ_FOREACH(us, &upnp_services, us_link)
182 us->us_received(buf, size, conn, &ip);
183 }
184 }
185
186 while (delay_ms == 0) {
187 pthread_mutex_lock(&upnp_lock);
188 data = TAILQ_FIRST(&upnp_data_write);
189 if (data) {
190 delay_ms = data->delay_ms;
191 data->delay_ms = 0;
192 if (!delay_ms) {
193 TAILQ_REMOVE(&upnp_data_write, data, data_link);
194 } else {
195 data = NULL;
196 }
197 }
198 pthread_mutex_unlock(&upnp_lock);
199 if (data == NULL)
200 break;
201 upnp_dump_data(data);
202 udp_write_queue(data->from_multicast ? multicast : unicast,
203 &data->queue, &data->storage);
204 htsbuf_queue_flush(&data->queue);
205 free(data);
206 delay_ms = 0;
207 }
208 }
209
210 /* flush the write queue (byebye messages) */
211 while (1) {
212 pthread_mutex_lock(&upnp_lock);
213 data = TAILQ_FIRST(&upnp_data_write);
214 if (data)
215 TAILQ_REMOVE(&upnp_data_write, data, data_link);
216 pthread_mutex_unlock(&upnp_lock);
217 if (data == NULL)
218 break;
219 tvh_safe_usleep((long)data->delay_ms * 1000);
220 upnp_dump_data(data);
221 udp_write_queue(unicast, &data->queue, &data->storage);
222 htsbuf_queue_flush(&data->queue);
223 free(data);
224 }
225
226 error:
227 atomic_set(&upnp_running, 0);
228 tvhpoll_destroy(poll);
229 udp_close(unicast);
230 udp_close(multicast);
231 return NULL;
232 }
233
234 /*
235 * Fire up UPnP server
236 */
237 void
upnp_server_init(const char * bindaddr)238 upnp_server_init(const char *bindaddr)
239 {
240 int r;
241
242 memset(&upnp_ipv4_multicast, 0, sizeof(upnp_ipv4_multicast));
243 upnp_ipv4_multicast.ss_family = AF_INET;
244 IP_AS_V4(upnp_ipv4_multicast, port) = htons(1900);
245 r = inet_pton(AF_INET, "239.255.255.250", &IP_AS_V4(upnp_ipv4_multicast, addr));
246 assert(r);
247
248 pthread_mutex_init(&upnp_lock, NULL);
249 TAILQ_INIT(&upnp_data_write);
250 TAILQ_INIT(&upnp_services);
251 atomic_set(&upnp_running, 1);
252 tvhthread_create(&upnp_tid, NULL, upnp_thread, (char *)bindaddr, "upnp");
253 }
254
255 void
upnp_server_done(void)256 upnp_server_done(void)
257 {
258 upnp_data_t *data;
259 upnp_service_t *us;
260
261 atomic_set(&upnp_running, 0);
262 pthread_kill(upnp_tid, SIGTERM);
263 pthread_join(upnp_tid, NULL);
264 while ((us = TAILQ_FIRST(&upnp_services)) != NULL)
265 upnp_service_destroy(us);
266 while ((data = TAILQ_FIRST(&upnp_data_write)) != NULL) {
267 TAILQ_REMOVE(&upnp_data_write, data, data_link);
268 htsbuf_queue_flush(&data->queue);
269 free(data);
270 }
271 }
272