125
|
1 /*
|
|
2 * ushare.c : GeeXboX uShare UPnP Media Server.
|
|
3 * Originally developped for the GeeXboX project.
|
|
4 * Parts of the code are originated from GMediaServer from Oskar Liljeblad.
|
|
5 * Copyright (C) 2005-2007 Benjamin Zores <ben@geexbox.org>
|
|
6 *
|
|
7 * This program is free software; you can redistribute it and/or modify
|
|
8 * it under the terms of the GNU General Public License as published by
|
|
9 * the Free Software Foundation; either version 2 of the License, or
|
|
10 * (at your option) any later version.
|
|
11 *
|
|
12 * This program is distributed in the hope that it will be useful,
|
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15 * GNU Library General Public License for more details.
|
|
16 *
|
|
17 * You should have received a copy of the GNU General Public License along
|
|
18 * with this program; if not, write to the Free Software Foundation,
|
|
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
20 */
|
|
21
|
|
22 #include <stdio.h>
|
|
23 #include <signal.h>
|
|
24 #include <string.h>
|
|
25 #include <stdlib.h>
|
|
26 #include <stdarg.h>
|
|
27 #include <unistd.h>
|
|
28 #include <errno.h>
|
|
29 #include <getopt.h>
|
|
30
|
|
31 #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__))
|
|
32 #include <sys/socket.h>
|
|
33 #include <sys/sysctl.h>
|
|
34 #include <net/if_dl.h>
|
|
35 #endif
|
|
36
|
|
37 #if (defined(__APPLE__))
|
|
38 #include <net/route.h>
|
|
39 #endif
|
|
40
|
|
41 #include <net/if.h>
|
|
42 #include <sys/ioctl.h>
|
|
43 #include <sys/types.h>
|
|
44 #include <sys/stat.h>
|
|
45 #include <stdbool.h>
|
|
46 #include <fcntl.h>
|
|
47
|
|
48 #ifdef HAVE_IFADDRS_H
|
|
49 #include <ifaddrs.h>
|
|
50 #endif
|
|
51
|
|
52 #if (defined(__unix__) || defined(unix)) && !defined(USG)
|
|
53 #include <sys/param.h>
|
|
54 #endif
|
|
55
|
|
56 #include <upnp/upnp.h>
|
|
57 #include <upnp/upnptools.h>
|
|
58
|
|
59 #if (defined(HAVE_SETLOCALE) && defined(CONFIG_NLS))
|
|
60 # include <locale.h>
|
|
61 #endif
|
|
62
|
|
63 #include "config.h"
|
|
64 #include "ushare.h"
|
|
65 #include "services.h"
|
|
66 #include "http.h"
|
|
67 #include "metadata.h"
|
|
68 #include "util_iconv.h"
|
|
69 #include "content.h"
|
|
70 #include "cfgparser.h"
|
|
71 #include "gettext.h"
|
|
72 #include "trace.h"
|
|
73 #include "buffer.h"
|
|
74 #include "ctrl_telnet.h"
|
|
75 #include "recpt1.h"
|
|
76
|
|
77 struct ushare_t *ut = NULL;
|
|
78
|
|
79 static struct ushare_t * ushare_new (void)
|
|
80 __attribute__ ((malloc));
|
|
81
|
|
82 static struct ushare_t *
|
|
83 ushare_new (void)
|
|
84 {
|
|
85 struct ushare_t *ut = (struct ushare_t *) malloc (sizeof (struct ushare_t));
|
|
86 if (!ut)
|
|
87 return NULL;
|
|
88
|
|
89 ut->name = strdup (DEFAULT_USHARE_NAME);
|
|
90 ut->interface = strdup (DEFAULT_USHARE_IFACE);
|
|
91 ut->model_name = strdup (DEFAULT_USHARE_NAME);
|
|
92 ut->contentlist = NULL;
|
|
93 ut->rb = rbinit (rb_compare, NULL);
|
|
94 ut->root_entry = NULL;
|
|
95 ut->nr_entries = 0;
|
|
96 ut->starting_id = STARTING_ENTRY_ID_DEFAULT;
|
|
97 ut->init = 0;
|
|
98 ut->dev = 0;
|
|
99 ut->udn = NULL;
|
|
100 ut->ip = NULL;
|
|
101 ut->port = 0; /* Randomly attributed by libupnp */
|
|
102 ut->telnet_port = CTRL_TELNET_PORT;
|
|
103 ut->presentation = NULL;
|
|
104 ut->use_presentation = true;
|
|
105 ut->use_telnet = true;
|
|
106 #ifdef HAVE_DLNA
|
|
107 ut->dlna_enabled = false;
|
|
108 ut->dlna = NULL;
|
|
109 ut->dlna_flags = DLNA_ORG_FLAG_STREAMING_TRANSFER_MODE |
|
|
110 DLNA_ORG_FLAG_BACKGROUND_TRANSFERT_MODE |
|
|
111 DLNA_ORG_FLAG_CONNECTION_STALL |
|
|
112 DLNA_ORG_FLAG_DLNA_V15;
|
|
113 #endif /* HAVE_DLNA */
|
|
114 ut->xbox360 = false;
|
|
115 ut->verbose = false;
|
|
116 ut->daemon = false;
|
|
117 ut->override_iconv_err = false;
|
|
118 ut->cfg_file = NULL;
|
|
119
|
|
120 pthread_mutex_init (&ut->termination_mutex, NULL);
|
|
121 pthread_cond_init (&ut->termination_cond, NULL);
|
|
122
|
|
123 return ut;
|
|
124 }
|
|
125
|
|
126 static void
|
|
127 ushare_free (struct ushare_t *ut)
|
|
128 {
|
|
129 if (!ut)
|
|
130 return;
|
|
131
|
|
132 if (ut->name)
|
|
133 free (ut->name);
|
|
134 if (ut->interface)
|
|
135 free (ut->interface);
|
|
136 if (ut->model_name)
|
|
137 free (ut->model_name);
|
|
138 if (ut->contentlist)
|
|
139 content_free (ut->contentlist);
|
|
140 if (ut->rb)
|
|
141 rbdestroy (ut->rb);
|
|
142 if (ut->root_entry)
|
|
143 upnp_entry_free (ut, ut->root_entry);
|
|
144 if (ut->udn)
|
|
145 free (ut->udn);
|
|
146 if (ut->ip)
|
|
147 free (ut->ip);
|
|
148 if (ut->presentation)
|
|
149 buffer_free (ut->presentation);
|
|
150 #ifdef HAVE_DLNA
|
|
151 if (ut->dlna_enabled)
|
|
152 {
|
|
153 if (ut->dlna)
|
|
154 dlna_uninit (ut->dlna);
|
|
155 ut->dlna = NULL;
|
|
156 }
|
|
157 #endif /* HAVE_DLNA */
|
|
158 if (ut->cfg_file)
|
|
159 free (ut->cfg_file);
|
|
160
|
|
161 pthread_cond_destroy (&ut->termination_cond);
|
|
162 pthread_mutex_destroy (&ut->termination_mutex);
|
|
163
|
|
164 free (ut);
|
|
165 }
|
|
166
|
|
167 static void
|
|
168 ushare_signal_exit (void)
|
|
169 {
|
|
170 pthread_mutex_lock (&ut->termination_mutex);
|
|
171 pthread_cond_signal (&ut->termination_cond);
|
|
172 pthread_mutex_unlock (&ut->termination_mutex);
|
|
173 }
|
|
174
|
|
175 static void
|
|
176 handle_action_request (struct Upnp_Action_Request *request)
|
|
177 {
|
|
178 struct service_t *service;
|
|
179 struct service_action_t *action;
|
|
180 char val[256];
|
|
181 uint32_t ip;
|
|
182
|
|
183 if (!request || !ut)
|
|
184 return;
|
|
185
|
|
186 if (request->ErrCode != UPNP_E_SUCCESS)
|
|
187 return;
|
|
188
|
|
189 if (strcmp (request->DevUDN + 5, ut->udn))
|
|
190 return;
|
|
191
|
|
192 ip = request->CtrlPtIPAddr.s_addr;
|
|
193 ip = ntohl (ip);
|
|
194 sprintf (val, "%d.%d.%d.%d",
|
|
195 (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
|
|
196
|
|
197 if (ut->verbose)
|
|
198 {
|
|
199 DOMString str = ixmlPrintDocument (request->ActionRequest);
|
|
200 log_verbose ("***************************************************\n");
|
|
201 log_verbose ("** New Action Request **\n");
|
|
202 log_verbose ("***************************************************\n");
|
|
203 log_verbose ("ServiceID: %s\n", request->ServiceID);
|
|
204 log_verbose ("ActionName: %s\n", request->ActionName);
|
|
205 log_verbose ("CtrlPtIP: %s\n", val);
|
|
206 log_verbose ("Action Request:\n%s\n", str);
|
|
207 ixmlFreeDOMString (str);
|
|
208 }
|
|
209
|
|
210 if (find_service_action (request, &service, &action))
|
|
211 {
|
|
212 struct action_event_t event;
|
|
213
|
|
214 event.request = request;
|
|
215 event.status = true;
|
|
216 event.service = service;
|
|
217
|
|
218 if (action->function (&event) && event.status)
|
|
219 request->ErrCode = UPNP_E_SUCCESS;
|
|
220
|
|
221 if (ut->verbose)
|
|
222 {
|
|
223 DOMString str = ixmlPrintDocument (request->ActionResult);
|
|
224 log_verbose ("Action Result:\n%s", str);
|
|
225 log_verbose ("***************************************************\n");
|
|
226 log_verbose ("\n");
|
|
227 ixmlFreeDOMString (str);
|
|
228 }
|
|
229
|
|
230 return;
|
|
231 }
|
|
232
|
|
233 if (service) /* Invalid Action name */
|
|
234 strcpy (request->ErrStr, "Unknown Service Action");
|
|
235 else /* Invalid Service name */
|
|
236 strcpy (request->ErrStr, "Unknown Service ID");
|
|
237
|
|
238 request->ActionResult = NULL;
|
|
239 request->ErrCode = UPNP_SOAP_E_INVALID_ACTION;
|
|
240 }
|
|
241
|
|
242 static int
|
|
243 device_callback_event_handler (Upnp_EventType type, void *event,
|
|
244 void *cookie __attribute__((unused)))
|
|
245 {
|
|
246 switch (type)
|
|
247 {
|
|
248 case UPNP_CONTROL_ACTION_REQUEST:
|
|
249 handle_action_request ((struct Upnp_Action_Request *) event);
|
|
250 break;
|
|
251 case UPNP_CONTROL_ACTION_COMPLETE:
|
|
252 case UPNP_EVENT_SUBSCRIPTION_REQUEST:
|
|
253 case UPNP_CONTROL_GET_VAR_REQUEST:
|
|
254 break;
|
|
255 default:
|
|
256 break;
|
|
257 }
|
|
258
|
|
259 return 0;
|
|
260 }
|
|
261
|
|
262 static int
|
|
263 finish_upnp (struct ushare_t *ut)
|
|
264 {
|
|
265 if (!ut)
|
|
266 return -1;
|
|
267
|
|
268 log_info (_("Stopping UPnP Service ...\n"));
|
|
269 UpnpUnRegisterRootDevice (ut->dev);
|
|
270 UpnpFinish ();
|
|
271
|
|
272 return UPNP_E_SUCCESS;
|
|
273 }
|
|
274
|
|
275 static int
|
|
276 init_upnp (struct ushare_t *ut)
|
|
277 {
|
|
278 char *description = NULL;
|
|
279 int res;
|
|
280 size_t len;
|
|
281
|
|
282 if (!ut || !ut->name || !ut->udn || !ut->ip)
|
|
283 return -1;
|
|
284
|
|
285 #ifdef HAVE_DLNA
|
|
286 if (ut->dlna_enabled)
|
|
287 {
|
|
288 len = 0;
|
|
289 description =
|
|
290 dlna_dms_description_get (ut->name,
|
|
291 "GeeXboX Team",
|
|
292 "http://ushare.geexbox.org/",
|
|
293 "uShare : DLNA Media Server",
|
|
294 ut->model_name,
|
|
295 "001",
|
|
296 "http://ushare.geexbox.org/",
|
|
297 "USHARE-01",
|
|
298 ut->udn,
|
|
299 "/web/ushare.html",
|
|
300 "/web/cms.xml",
|
|
301 "/web/cms_control",
|
|
302 "/web/cms_event",
|
|
303 "/web/cds.xml",
|
|
304 "/web/cds_control",
|
|
305 "/web/cds_event");
|
|
306 if (!description)
|
|
307 return -1;
|
|
308 }
|
|
309 else
|
|
310 {
|
|
311 #endif /* HAVE_DLNA */
|
|
312 len = strlen (UPNP_DESCRIPTION) + strlen (ut->name)
|
|
313 + strlen (ut->model_name) + strlen (ut->udn) + 1;
|
|
314 description = (char *) malloc (len * sizeof (char));
|
|
315 memset (description, 0, len);
|
|
316 sprintf (description, UPNP_DESCRIPTION, ut->name, ut->model_name, ut->udn);
|
|
317 #ifdef HAVE_DLNA
|
|
318 }
|
|
319 #endif /* HAVE_DLNA */
|
|
320
|
|
321 log_info (_("Initializing UPnP subsystem ...\n"));
|
|
322 res = UpnpInit (ut->ip, ut->port);
|
|
323 if (res != UPNP_E_SUCCESS)
|
|
324 {
|
|
325 log_error (_("Cannot initialize UPnP subsystem\n"));
|
|
326 return -1;
|
|
327 }
|
|
328
|
|
329 if (UpnpSetMaxContentLength (UPNP_MAX_CONTENT_LENGTH) != UPNP_E_SUCCESS)
|
|
330 log_info (_("Could not set Max content UPnP\n"));
|
|
331
|
|
332 if (ut->xbox360)
|
|
333 log_info (_("Starting in XboX 360 compliant profile ...\n"));
|
|
334
|
|
335 #ifdef HAVE_DLNA
|
|
336 if (ut->dlna_enabled)
|
|
337 {
|
|
338 log_info (_("Starting in DLNA compliant profile ...\n"));
|
|
339 ut->dlna = dlna_init ();
|
|
340 dlna_set_verbosity (ut->dlna, ut->verbose ? 1 : 0);
|
|
341 dlna_set_extension_check (ut->dlna, 1);
|
|
342 dlna_register_all_media_profiles (ut->dlna);
|
|
343 }
|
|
344 #endif /* HAVE_DLNA */
|
|
345
|
|
346 ut->port = UpnpGetServerPort();
|
|
347 log_info (_("UPnP MediaServer listening on %s:%d\n"),
|
|
348 UpnpGetServerIpAddress (), ut->port);
|
|
349
|
|
350 UpnpEnableWebserver (TRUE);
|
|
351
|
|
352 res = UpnpSetVirtualDirCallbacks (&virtual_dir_callbacks);
|
|
353 if (res != UPNP_E_SUCCESS)
|
|
354 {
|
|
355 log_error (_("Cannot set virtual directory callbacks\n"));
|
|
356 free (description);
|
|
357 return -1;
|
|
358 }
|
|
359
|
|
360 res = UpnpAddVirtualDir (VIRTUAL_DIR);
|
|
361 if (res != UPNP_E_SUCCESS)
|
|
362 {
|
|
363 log_error (_("Cannot add virtual directory for web server\n"));
|
|
364 free (description);
|
|
365 return -1;
|
|
366 }
|
|
367
|
|
368 res = UpnpRegisterRootDevice2 (UPNPREG_BUF_DESC, description, 0, 1,
|
|
369 device_callback_event_handler,
|
|
370 NULL, &(ut->dev));
|
|
371 if (res != UPNP_E_SUCCESS)
|
|
372 {
|
|
373 log_error (_("Cannot register UPnP device\n"));
|
|
374 free (description);
|
|
375 return -1;
|
|
376 }
|
|
377
|
|
378 res = UpnpUnRegisterRootDevice (ut->dev);
|
|
379 if (res != UPNP_E_SUCCESS)
|
|
380 {
|
|
381 log_error (_("Cannot unregister UPnP device\n"));
|
|
382 free (description);
|
|
383 return -1;
|
|
384 }
|
|
385
|
|
386 res = UpnpRegisterRootDevice2 (UPNPREG_BUF_DESC, description, 0, 1,
|
|
387 device_callback_event_handler,
|
|
388 NULL, &(ut->dev));
|
|
389 if (res != UPNP_E_SUCCESS)
|
|
390 {
|
|
391 log_error (_("Cannot register UPnP device\n"));
|
|
392 free (description);
|
|
393 return -1;
|
|
394 }
|
|
395
|
|
396 log_info (_("Sending UPnP advertisement for device ...\n"));
|
|
397 UpnpSendAdvertisement (ut->dev, 1800);
|
|
398
|
|
399 log_info (_("Listening for control point connections ...\n"));
|
|
400
|
|
401 if (description)
|
|
402 free (description);
|
|
403
|
|
404 return 0;
|
|
405 }
|
|
406
|
|
407 static bool
|
|
408 has_iface (char *interface)
|
|
409 {
|
|
410 #ifdef HAVE_IFADDRS_H
|
|
411 struct ifaddrs *itflist, *itf;
|
|
412
|
|
413 if (!interface)
|
|
414 return false;
|
|
415
|
|
416 if (getifaddrs (&itflist) < 0)
|
|
417 {
|
|
418 perror ("getifaddrs");
|
|
419 return false;
|
|
420 }
|
|
421
|
|
422 itf = itflist;
|
|
423 while (itf)
|
|
424 {
|
|
425 if ((itf->ifa_flags & IFF_UP)
|
|
426 && !strncmp (itf->ifa_name, interface, IFNAMSIZ))
|
|
427 {
|
|
428 log_error (_("Interface %s is down.\n"), interface);
|
|
429 log_error (_("Recheck uShare's configuration and try again !\n"));
|
|
430 freeifaddrs (itflist);
|
|
431 return true;
|
|
432 }
|
|
433 itf = itf->ifa_next;
|
|
434 }
|
|
435
|
|
436 freeifaddrs (itf);
|
|
437 #else
|
|
438 int sock, i, n;
|
|
439 struct ifconf ifc;
|
|
440 struct ifreq ifr;
|
|
441 char buff[8192];
|
|
442
|
|
443 if (!interface)
|
|
444 return false;
|
|
445
|
|
446 /* determine UDN according to MAC address */
|
|
447 sock = socket (AF_INET, SOCK_STREAM, 0);
|
|
448 if (sock < 0)
|
|
449 {
|
|
450 perror ("socket");
|
|
451 return false;
|
|
452 }
|
|
453
|
|
454 /* get list of available interfaces */
|
|
455 ifc.ifc_len = sizeof (buff);
|
|
456 ifc.ifc_buf = buff;
|
|
457
|
|
458 if (ioctl (sock, SIOCGIFCONF, &ifc) < 0)
|
|
459 {
|
|
460 perror ("ioctl");
|
|
461 close (sock);
|
|
462 return false;
|
|
463 }
|
|
464
|
|
465 n = ifc.ifc_len / sizeof (struct ifreq);
|
|
466 for (i = n - 1 ; i >= 0 ; i--)
|
|
467 {
|
|
468 ifr = ifc.ifc_req[i];
|
|
469
|
|
470 if (strncmp (ifr.ifr_name, interface, IFNAMSIZ))
|
|
471 continue;
|
|
472
|
|
473 if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
|
|
474 {
|
|
475 perror ("ioctl");
|
|
476 close (sock);
|
|
477 return false;
|
|
478 }
|
|
479
|
|
480 if (!(ifr.ifr_flags & IFF_UP))
|
|
481 {
|
|
482 /* interface is down */
|
|
483 log_error (_("Interface %s is down.\n"), interface);
|
|
484 log_error (_("Recheck uShare's configuration and try again !\n"));
|
|
485 close (sock);
|
|
486 return false;
|
|
487 }
|
|
488
|
|
489 /* found right interface */
|
|
490 close (sock);
|
|
491 return true;
|
|
492 }
|
|
493 close (sock);
|
|
494 #endif
|
|
495
|
|
496 log_error (_("Can't find interface %s.\n"),interface);
|
|
497 log_error (_("Recheck uShare's configuration and try again !\n"));
|
|
498
|
|
499 return false;
|
|
500 }
|
|
501
|
|
502 static char *
|
|
503 create_udn (char *interface)
|
|
504 {
|
|
505 int sock = -1;
|
|
506 char *buf;
|
|
507 unsigned char *ptr;
|
|
508
|
|
509 #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__))
|
|
510 int mib[6];
|
|
511 size_t len;
|
|
512 struct if_msghdr *ifm;
|
|
513 struct sockaddr_dl *sdl;
|
|
514 #else /* Linux */
|
|
515 struct ifreq ifr;
|
|
516 #endif
|
|
517
|
|
518 if (!interface)
|
|
519 return NULL;
|
|
520
|
|
521 #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__))
|
|
522 mib[0] = CTL_NET;
|
|
523 mib[1] = AF_ROUTE;
|
|
524 mib[2] = 0;
|
|
525 mib[3] = AF_LINK;
|
|
526 mib[4] = NET_RT_IFLIST;
|
|
527
|
|
528 mib[5] = if_nametoindex (interface);
|
|
529 if (mib[5] == 0)
|
|
530 {
|
|
531 perror ("if_nametoindex");
|
|
532 return NULL;
|
|
533 }
|
|
534
|
|
535 if (sysctl (mib, 6, NULL, &len, NULL, 0) < 0)
|
|
536 {
|
|
537 perror ("sysctl");
|
|
538 return NULL;
|
|
539 }
|
|
540
|
|
541 buf = malloc (len);
|
|
542 if (sysctl (mib, 6, buf, &len, NULL, 0) < 0)
|
|
543 {
|
|
544 perror ("sysctl");
|
|
545 return NULL;
|
|
546 }
|
|
547
|
|
548 ifm = (struct if_msghdr *) buf;
|
|
549 sdl = (struct sockaddr_dl*) (ifm + 1);
|
|
550 ptr = (unsigned char *) LLADDR (sdl);
|
|
551 #else /* Linux */
|
|
552 /* determine UDN according to MAC address */
|
|
553 sock = socket (AF_INET, SOCK_STREAM, 0);
|
|
554 if (sock < 0)
|
|
555 {
|
|
556 perror ("socket");
|
|
557 return NULL;
|
|
558 }
|
|
559
|
|
560 strcpy (ifr.ifr_name, interface);
|
|
561 strcpy (ifr.ifr_hwaddr.sa_data, "");
|
|
562
|
|
563 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
|
|
564 {
|
|
565 perror ("ioctl");
|
|
566 return NULL;
|
|
567 }
|
|
568
|
|
569 buf = (char *) malloc (64 * sizeof (char));
|
|
570 memset (buf, 0, 64);
|
|
571 ptr = (unsigned char *) ifr.ifr_hwaddr.sa_data;
|
|
572 #endif /* (defined(BSD) || defined(__FreeBSD__)) */
|
|
573
|
|
574 snprintf (buf, 64, "%s-%02x%02x%02x%02x%02x%02x", DEFAULT_UUID,
|
|
575 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
|
|
576 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377));
|
|
577
|
|
578 if (sock)
|
|
579 close (sock);
|
|
580
|
|
581 return buf;
|
|
582 }
|
|
583
|
|
584 static char *
|
|
585 get_iface_address (char *interface)
|
|
586 {
|
|
587 int sock;
|
|
588 uint32_t ip;
|
|
589 struct ifreq ifr;
|
|
590 char *val;
|
|
591
|
|
592 if (!interface)
|
|
593 return NULL;
|
|
594
|
|
595 /* determine UDN according to MAC address */
|
|
596 sock = socket (AF_INET, SOCK_STREAM, 0);
|
|
597 if (sock < 0)
|
|
598 {
|
|
599 perror ("socket");
|
|
600 return NULL;
|
|
601 }
|
|
602
|
|
603 strcpy (ifr.ifr_name, interface);
|
|
604 ifr.ifr_addr.sa_family = AF_INET;
|
|
605
|
|
606 if (ioctl (sock, SIOCGIFADDR, &ifr) < 0)
|
|
607 {
|
|
608 perror ("ioctl");
|
|
609 close (sock);
|
|
610 return NULL;
|
|
611 }
|
|
612
|
|
613 val = (char *) malloc (16 * sizeof (char));
|
|
614 ip = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
|
|
615 ip = ntohl (ip);
|
|
616 sprintf (val, "%d.%d.%d.%d",
|
|
617 (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
|
|
618
|
|
619 close (sock);
|
|
620
|
|
621 return val;
|
|
622 }
|
|
623
|
|
624 static int
|
|
625 restart_upnp (struct ushare_t *ut)
|
|
626 {
|
|
627 finish_upnp (ut);
|
|
628
|
|
629 if (ut->udn)
|
|
630 free (ut->udn);
|
|
631 ut->udn = create_udn (ut->interface);
|
|
632 if (!ut->udn)
|
|
633 return -1;
|
|
634
|
|
635 if (ut->ip)
|
|
636 free (ut->ip);
|
|
637 ut->ip = get_iface_address (ut->interface);
|
|
638 if (!ut->ip)
|
|
639 return -1;
|
|
640
|
|
641 return (init_upnp (ut));
|
|
642 }
|
|
643
|
|
644 static void
|
|
645 UPnPBreak (int s __attribute__ ((unused)))
|
|
646 {
|
|
647 ushare_signal_exit ();
|
|
648 }
|
|
649
|
|
650 static void
|
|
651 reload_config (int s __attribute__ ((unused)))
|
|
652 {
|
|
653 struct ushare_t *ut2;
|
|
654 bool reload = false;
|
|
655
|
|
656 log_info (_("Reloading configuration...\n"));
|
|
657
|
|
658 ut2 = ushare_new ();
|
|
659 if (!ut || !ut2)
|
|
660 return;
|
|
661
|
|
662 if (parse_config_file (ut2) < 0)
|
|
663 return;
|
|
664
|
|
665 if (ut->name && strcmp (ut->name, ut2->name))
|
|
666 {
|
|
667 free (ut->name);
|
|
668 ut->name = ut2->name;
|
|
669 ut2->name = NULL;
|
|
670 reload = true;
|
|
671 }
|
|
672
|
|
673 if (ut->interface && strcmp (ut->interface, ut2->interface))
|
|
674 {
|
|
675 if (!has_iface (ut2->interface))
|
|
676 {
|
|
677 ushare_free (ut2);
|
|
678 raise (SIGINT);
|
|
679 }
|
|
680 else
|
|
681 {
|
|
682 free (ut->interface);
|
|
683 ut->interface = ut2->interface;
|
|
684 ut2->interface = NULL;
|
|
685 reload = true;
|
|
686 }
|
|
687 }
|
|
688
|
|
689 if (ut->port != ut2->port)
|
|
690 {
|
|
691 ut->port = ut2->port;
|
|
692 reload = true;
|
|
693 }
|
|
694
|
|
695 if (reload)
|
|
696 {
|
|
697 if (restart_upnp (ut) < 0)
|
|
698 {
|
|
699 ushare_free (ut2);
|
|
700 raise (SIGINT);
|
|
701 }
|
|
702 }
|
|
703
|
|
704 if (ut->contentlist)
|
|
705 content_free (ut->contentlist);
|
|
706 ut->contentlist = ut2->contentlist;
|
|
707 ut2->contentlist = NULL;
|
|
708 ushare_free (ut2);
|
|
709
|
|
710 if (ut->contentlist)
|
|
711 {
|
|
712 free_metadata_list (ut);
|
|
713 build_metadata_list (ut);
|
|
714 }
|
|
715 else
|
|
716 {
|
|
717 log_error (_("Error: no content directory to be shared.\n"));
|
|
718 raise (SIGINT);
|
|
719 }
|
|
720 }
|
|
721
|
|
722 inline void
|
|
723 display_headers (void)
|
|
724 {
|
|
725 printf (_("%s (version %s), a lightweight UPnP A/V and DLNA Media Server.\n"),
|
|
726 PACKAGE_NAME, VERSION);
|
|
727 printf (_("Benjamin Zores (C) 2005-2007, for GeeXboX Team.\n"));
|
|
728 printf (_("See http://ushare.geexbox.org/ for updates.\n"));
|
|
729 }
|
|
730
|
|
731 inline static void
|
|
732 setup_i18n(void)
|
|
733 {
|
|
734 #ifdef CONFIG_NLS
|
|
735 #ifdef HAVE_SETLOCALE
|
|
736 setlocale (LC_ALL, "");
|
|
737 #endif
|
|
738 #if (!defined(BSD) && !defined(__FreeBSD__))
|
|
739 bindtextdomain (PACKAGE, LOCALEDIR);
|
|
740 #endif
|
|
741 textdomain (PACKAGE);
|
|
742 #endif
|
|
743 }
|
|
744
|
|
745 #define SHUTDOWN_MSG _("Server is shutting down: other clients will be notified soon, Bye bye ...\n")
|
|
746
|
|
747 static void
|
|
748 ushare_kill (ctrl_telnet_client *client,
|
|
749 int argc __attribute__((unused)),
|
|
750 char **argv __attribute__((unused)))
|
|
751 {
|
|
752 if (ut->use_telnet)
|
|
753 {
|
|
754 ctrl_telnet_client_send (client, SHUTDOWN_MSG);
|
|
755 client->exiting = true;
|
|
756 }
|
|
757 ushare_signal_exit ();
|
|
758 }
|
|
759
|
|
760 //main (int argc, char **argv)
|
|
761 void *
|
|
762 dlna_startup (void *p)
|
|
763 {
|
|
764 ut = ushare_new ();
|
|
765 log_verbose ("dlna_startup() start\n");
|
|
766
|
|
767 if (!ut)
|
|
768 return NULL;
|
|
769
|
|
770 setup_i18n ();
|
|
771 setup_iconv ();
|
|
772
|
|
773 #if 0
|
|
774 /* Parse args before cfg file, as we may override the default file */
|
|
775 if (parse_command_line (ut, argc, argv) < 0)
|
|
776 {
|
|
777 ushare_free (ut);
|
|
778 return NULL;
|
|
779 }
|
|
780 #endif
|
|
781
|
|
782 if (parse_config_file (ut) < 0)
|
|
783 {
|
|
784 /* fprintf here, because syslog not yet ready */
|
|
785 fprintf (stderr, _("Warning: can't parse file \"%s\".\n"),
|
|
786 ut->cfg_file ? ut->cfg_file : SYSCONFDIR "/" USHARE_CONFIG_FILE);
|
|
787 }
|
|
788 ut->verbose = true;
|
|
789 ut->port = 0;
|
|
790 ut->use_presentation = false;
|
|
791 ut->use_telnet = false;
|
|
792 ut->dlna_enabled = true;
|
|
793 ut->override_iconv_err = false;
|
|
794 ut->xbox360 = true;
|
|
795 ut->daemon = false;
|
|
796 //ut->interface = "192.168.1.34";
|
|
797 ut->contentlist = "/tmp";
|
|
798
|
|
799 if (ut->xbox360)
|
|
800 {
|
|
801 char *name;
|
|
802
|
|
803 name = malloc (strlen (XBOX_MODEL_NAME) + strlen (ut->model_name) + 4);
|
|
804 sprintf (name, "%s (%s)", XBOX_MODEL_NAME, ut->model_name);
|
|
805 free (ut->model_name);
|
|
806 ut->model_name = strdup (name);
|
|
807 free (name);
|
|
808
|
|
809 ut->starting_id = STARTING_ENTRY_ID_XBOX360;
|
|
810 }
|
|
811
|
|
812 if (ut->daemon)
|
|
813 {
|
|
814 /* starting syslog feature as soon as possible */
|
|
815 start_log ();
|
|
816 }
|
|
817
|
|
818 if (!ut->contentlist)
|
|
819 {
|
|
820 log_error (_("Error: no content directory to be shared.\n"));
|
|
821 ushare_free (ut);
|
|
822 return NULL;
|
|
823 }
|
|
824
|
|
825 if (!has_iface (ut->interface))
|
|
826 {
|
|
827 ushare_free (ut);
|
|
828 return NULL;
|
|
829 }
|
|
830
|
|
831 ut->udn = create_udn (ut->interface);
|
|
832 if (!ut->udn)
|
|
833 {
|
|
834 ushare_free (ut);
|
|
835 return NULL;
|
|
836 }
|
|
837
|
|
838 ut->ip = get_iface_address (ut->interface);
|
|
839 if (!ut->ip)
|
|
840 {
|
|
841 ushare_free (ut);
|
|
842 return NULL;
|
|
843 }
|
|
844
|
|
845 if (ut->daemon)
|
|
846 {
|
|
847 int err;
|
|
848 err = daemon (0, 0);
|
|
849 if (err == -1)
|
|
850 {
|
|
851 log_error (_("Error: failed to daemonize program : %s\n"),
|
|
852 strerror (err));
|
|
853 ushare_free (ut);
|
|
854 return NULL;
|
|
855 }
|
|
856 }
|
|
857 else
|
|
858 {
|
|
859 display_headers ();
|
|
860 }
|
|
861
|
|
862 #if 0
|
|
863 signal (SIGINT, UPnPBreak);
|
|
864 signal (SIGTERM, UPnPBreak);
|
|
865 signal (SIGUSR1, UPnPBreak);
|
|
866 signal (SIGUSR2, UPnPBreak);
|
|
867 signal (SIGPIPE, UPnPBreak);
|
|
868 signal (SIGHUP, reload_config);
|
|
869 #endif
|
|
870
|
|
871 if (ut->use_telnet)
|
|
872 {
|
|
873 if (ctrl_telnet_start (ut->telnet_port) < 0)
|
|
874 {
|
|
875 ushare_free (ut);
|
|
876 return NULL;
|
|
877 }
|
|
878
|
|
879 ctrl_telnet_register ("kill", ushare_kill,
|
|
880 _("Terminates the uShare server"));
|
|
881 }
|
|
882 log_verbose ("init_upnp() start\n");
|
|
883
|
|
884 if (init_upnp (ut) < 0)
|
|
885 {
|
|
886 finish_upnp (ut);
|
|
887 ushare_free (ut);
|
|
888 return NULL;
|
|
889 }
|
|
890
|
|
891 build_metadata_list (ut);
|
|
892
|
|
893 log_verbose ("uShare mutex lock.\n");
|
|
894 /* Let main sleep until it's time to die... */
|
|
895 pthread_mutex_lock (&ut->termination_mutex);
|
|
896 log_verbose ("uShare cond wait.\n");
|
|
897 pthread_cond_wait (&ut->termination_cond, &ut->termination_mutex);
|
|
898 pthread_mutex_unlock (&ut->termination_mutex);
|
|
899 log_verbose ("uShare finish.\n");
|
|
900
|
|
901 if (ut->use_telnet)
|
|
902 ctrl_telnet_stop ();
|
|
903 finish_upnp (ut);
|
|
904 free_metadata_list (ut);
|
|
905 ushare_free (ut);
|
|
906 finish_iconv ();
|
|
907
|
|
908 log_verbose ("dlna_start() finish\n");
|
|
909 /* it should never be executed */
|
|
910 return NULL;
|
|
911 }
|