/* * ushare.c : GeeXboX uShare UPnP Media Server. * Originally developped for the GeeXboX project. * Parts of the code are originated from GMediaServer from Oskar Liljeblad. * Copyright (C) 2005-2007 Benjamin Zores * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of 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 of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #if (defined(_HAVEMACOS) ) #undef CONFIG_NLS #endif #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__)) #include #include #include #endif #if (defined(__APPLE__)) #include #endif #include #include #include #include #include #include #ifdef HAVE_IFADDRS_H #include #endif #if (defined(__unix__) || defined(unix)) && !defined(USG) #include #endif #include #include #include "config.h" #if (defined(HAVE_SETLOCALE) && defined(CONFIG_NLS)) # include #endif #include "ushare.h" #include "services.h" #include "http.h" #ifdef USE_BUNNY #include "bunny.h" #include "bunny_meta.h" #endif #include "metadata.h" #include "util_iconv.h" #include "content.h" #include "cfgparser.h" #include "gettext.h" #include "trace.h" #include "buffer.h" #include "ctrl_telnet.h" struct ushare_t *ut = NULL; static struct ushare_t * ushare_new (int argc, char **argv) __attribute__ ((malloc)); static struct ushare_t * ushare_new (int argc, char **argv) { struct ushare_t *ut = (struct ushare_t *) malloc (sizeof (struct ushare_t)); if (!ut) return NULL; ut->argc = argc; ut->argv = argv; ut->name = strdup (DEFAULT_USHARE_NAME); ut->interface = strdup (DEFAULT_USHARE_IFACE); ut->model_name = strdup (DEFAULT_USHARE_NAME); ut->contentlist = NULL; ut->rb = rbinit (rb_compare, NULL); ut->root_entry = NULL; ut->nr_entries = 0; ut->starting_id = STARTING_ENTRY_ID_DEFAULT; ut->init = false; ut->term = false; ut->dev = 0; ut->udn = NULL; ut->ip = NULL; ut->port = 0; /* Randomly attributed by libupnp */ ut->telnet_port = CTRL_TELNET_PORT; ut->presentation = NULL; ut->use_presentation = true; ut->use_telnet = true; #ifdef HAVE_DLNA ut->dlna_enabled = false; ut->dlna = NULL; ut->dlna_flags = DLNA_ORG_FLAG_STREAMING_TRANSFER_MODE | DLNA_ORG_FLAG_BACKGROUND_TRANSFERT_MODE | DLNA_ORG_FLAG_CONNECTION_STALL | DLNA_ORG_FLAG_DLNA_V15; #endif /* HAVE_DLNA */ ut->xbox360 = false; ut->verbose = true; ut->daemon = false; ut->override_iconv_err = false; #ifdef USE_BUNNY ut->bunny = false; ut->use_cache = true; // define this to true to get more debugging ut->verbose = true; ut->xml_doc = NULL; ut->dssObj = NULL; #endif ut->cfg_file = NULL; pthread_mutex_init (&ut->termination_mutex, NULL); pthread_cond_init (&ut->termination_cond, NULL); return ut; } static void ushare_free (struct ushare_t *ut) { if (!ut) return; if (ut->name) free (ut->name); if (ut->interface) free (ut->interface); if (ut->model_name) free (ut->model_name); if (ut->contentlist) content_free (ut->contentlist); if (ut->rb) rbdestroy (ut->rb); if (ut->root_entry) upnp_entry_free (ut, ut->root_entry); if (ut->udn) free (ut->udn); if (ut->ip) free (ut->ip); if (ut->presentation) buffer_free (ut->presentation); #ifdef HAVE_DLNA if (ut->dlna_enabled) { if (ut->dlna) dlna_uninit (ut->dlna); ut->dlna = NULL; } #endif /* HAVE_DLNA */ if (ut->cfg_file) free (ut->cfg_file); pthread_cond_destroy (&ut->termination_cond); pthread_mutex_destroy (&ut->termination_mutex); free (ut); } static void ushare_signal_exit (void) { pthread_mutex_lock (&ut->termination_mutex); pthread_cond_signal (&ut->termination_cond); pthread_mutex_unlock (&ut->termination_mutex); ut->term = true; } static void handle_action_request (UpnpActionRequest *request) { struct service_t *service; struct service_action_t *action; char val[256]; uint32_t ip; if (!request || !ut) return; if (UpnpActionRequest_get_ErrCode(request) != UPNP_E_SUCCESS) return; if (strcmp (UpnpActionRequest_get_DevUDN_cstr(request) + 5, ut->udn)) return; ip = (*(struct sockaddr_in *)UpnpActionRequest_get_CtrlPtIPAddr(request)).sin_addr.s_addr; ip = ntohl (ip); sprintf (val, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF); if (ut->verbose) { DOMString str = ixmlPrintDocument (UpnpActionRequest_get_ActionRequest(request)); log_verbose ("***************************************************\n"); log_verbose ("** New Action Request **\n"); log_verbose ("***************************************************\n"); log_verbose ("ServiceID: %s\n", UpnpActionRequest_get_ServiceID_cstr(request)); log_verbose ("ActionName: %s\n", UpnpActionRequest_get_ActionName_cstr(request)); log_verbose ("CtrlPtIP: %s\n", val); log_verbose ("Action Request:\n%s\n", str); ixmlFreeDOMString (str); } if (find_service_action (request, &service, &action)) { struct action_event_t event; event.request = request; event.status = true; event.service = service; if (action->function (&event) && event.status) UpnpActionRequest_set_ErrCode(request, UPNP_E_SUCCESS); if (ut->verbose) { DOMString str = ixmlPrintDocument (UpnpActionRequest_get_ActionResult(request)); log_verbose ("Action Result:\n%s", str); log_verbose ("***************************************************\n"); log_verbose ("\n"); ixmlFreeDOMString (str); } return; } if (service) /* Invalid Action name */ UpnpActionRequest_strcpy_ErrStr(request, "Unknown Service Action"); else /* Invalid Service name */ UpnpActionRequest_strcpy_ErrStr(request, "Unknown Service ID"); UpnpActionRequest_set_ActionResult(request, NULL); UpnpActionRequest_set_ErrCode(request, UPNP_SOAP_E_INVALID_ACTION); } static int device_callback_event_handler (Upnp_EventType type, const void *event, void *cookie __attribute__((unused))) { switch (type) { case UPNP_CONTROL_ACTION_REQUEST: handle_action_request ((UpnpActionRequest *) event); break; case UPNP_CONTROL_ACTION_COMPLETE: case UPNP_EVENT_SUBSCRIPTION_REQUEST: case UPNP_CONTROL_GET_VAR_REQUEST: break; default: break; } return 0; } static int finish_upnp (struct ushare_t *ut) { if (!ut) return -1; log_info (_("Stopping UPnP Service ...\n")); UpnpUnRegisterRootDevice (ut->dev); UpnpFinish (); return UPNP_E_SUCCESS; } static int init_upnp (struct ushare_t *ut) { char *description = NULL; int res; size_t len; if (!ut || !ut->name || !ut->udn || !ut->ip) return -1; #ifdef HAVE_DLNA if (ut->dlna_enabled) { len = 0; description = dlna_dms_description_get (ut->name, "Dwanta", "https://buuna.dwanta.com/", "bunnyuShare : DLNA Media Server", ut->model_name, "001", "https://buuna.dwanta.com/", "BUNNYUSHARE-01", ut->udn, "/web/ushare.html", "/web/cms.xml", "/web/cms_control", "/web/cms_event", "/web/cds.xml", "/web/cds_control", "/web/cds_event"); if (!description) return -1; } else { #endif /* HAVE_DLNA */ len = strlen (UPNP_DESCRIPTION) + strlen (ut->name) + strlen (ut->model_name) + strlen (ut->udn) + 1; description = (char *) malloc (len * sizeof (char)); memset (description, 0, len); sprintf (description, UPNP_DESCRIPTION, ut->name, ut->model_name, ut->udn); #ifdef HAVE_DLNA } #endif /* HAVE_DLNA */ log_info (_("Initializing UPnP subsystem ... %s\n"), ut->interface); res = UpnpInit2 (ut->interface, ut->port); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot initialize UPnP subsystem\n")); return -1; } if (UpnpSetMaxContentLength (UPNP_MAX_CONTENT_LENGTH) != UPNP_E_SUCCESS) log_info (_("Could not set Max content UPnP\n")); if (ut->xbox360) log_info (_("Starting in XboX 360 compliant profile ...\n")); #ifdef HAVE_DLNA if (ut->dlna_enabled) { log_info (_("Starting in DLNA compliant profile ...\n")); ut->dlna = dlna_init (); dlna_set_verbosity (ut->dlna, ut->verbose ? 1 : 0); dlna_set_extension_check (ut->dlna, 1); dlna_register_all_media_profiles (ut->dlna); } #endif /* HAVE_DLNA */ ut->port = UpnpGetServerPort(); log_info (_("UPnP MediaServer listening on %s:%d\n"), UpnpGetServerIpAddress (), ut->port); UpnpEnableWebserver (1); #define upnp_set_callback(cb, func) \ do { \ res = UpnpVirtualDir_set_##cb##Callback(func); \ if (res != UPNP_E_SUCCESS) \ { \ log_error (_("Cannot set virtual directory callbacks\n")); \ free (description); \ return -1; \ } \ } while(0) if( ut->bunny ) { log_error (_("Using Bunny!\n")); \ bunny_cache_seminit = semget( BUNNYKEY, 1, S_IRWXU ); if( bunny_cache_seminit ) semctl( bunny_cache_seminit, 0, IPC_RMID, 0 ); bunny_cache_seminit = semget( BUNNYKEY, 1, S_IRWXU | IPC_CREAT ); if( bunny_cache_seminit == -1 ) { log_verbose( "ERROR: cache semget" ); return -1; } semctl( bunny_cache_seminit, 0, SETVAL, 0 ); bunny_cache_semdata = semget( BUNNYKEY2, 1, S_IRWXU ); if( bunny_cache_semdata ) semctl( bunny_cache_semdata, 0, IPC_RMID, 0 ); bunny_cache_semdata = semget( BUNNYKEY2, 1, S_IRWXU | IPC_CREAT ); if( bunny_cache_semdata == -1 ) { log_verbose( "ERROR: cache semget" ); return -1; } semctl( bunny_cache_semdata, 0, SETVAL, 0 ); bunny_cache_sem = semget( BUNNYKEY3, 1, S_IRWXU ); if( bunny_cache_sem ) semctl( bunny_cache_sem, 0, IPC_RMID, 0 ); bunny_cache_sem = semget( BUNNYKEY3, 1, S_IRWXU | IPC_CREAT ); if( bunny_cache_sem == -1 ) { log_verbose( "ERROR: cache semget" ); return -1; } semctl( bunny_cache_sem, 0, SETVAL, 0 ); pthread_t tp; int a = 1; int rc = pthread_create( &tp, NULL, bunny_cache_thread, &a); struct sembuf semOp; semOp.sem_num = 0; semOp.sem_op = -1; semOp.sem_flg = 0; // wait for cache to run rc = semop( bunny_cache_seminit, &semOp, 1 ); upnp_set_callback(GetInfo, bunny_get_info); upnp_set_callback(Open, bunny_open); upnp_set_callback(Read, bunny_read); upnp_set_callback(Seek, bunny_seek); upnp_set_callback(Write, bunny_write); upnp_set_callback(Close, bunny_close); } else { log_error (_("Using HTTP!\n")); \ upnp_set_callback(GetInfo, http_get_info); upnp_set_callback(Open, http_open); upnp_set_callback(Read, http_read); upnp_set_callback(Seek, http_seek); upnp_set_callback(Write, http_write); upnp_set_callback(Close, http_close); } res = UpnpAddVirtualDir (VIRTUAL_DIR, NULL, NULL); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot add virtual directory for web server\n")); free (description); return -1; } res = UpnpRegisterRootDevice2 (UPNPREG_BUF_DESC, description, 0, 1, device_callback_event_handler, NULL, &(ut->dev)); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot register UPnP device\n")); free (description); return -1; } res = UpnpUnRegisterRootDevice (ut->dev); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot unregister UPnP device\n")); free (description); return -1; } res = UpnpRegisterRootDevice2 (UPNPREG_BUF_DESC, description, 0, 1, device_callback_event_handler, NULL, &(ut->dev)); if (res != UPNP_E_SUCCESS) { log_error (_("Cannot register UPnP device\n")); free (description); return -1; } log_info (_("Sending UPnP advertisement for device ...\n")); //UpnpSendAdvertisement (ut->dev, 1800); UpnpSendAdvertisement (ut->dev, 100); log_info (_("Listening for control point connections ...\n")); if (description) free (description); return 0; } static bool has_iface (char *interface) { #ifdef HAVE_IFADDRS_H struct ifaddrs *itflist, *itf; if (!interface) return false; if (getifaddrs (&itflist) < 0) { perror ("getifaddrs"); return false; } itf = itflist; while (itf) { if ((itf->ifa_flags & IFF_UP) //&& !strncmp (itf->ifa_name, interface, IFNAMSIZ)) // TESTING! && !strncmp (itf->ifa_name, interface, 4 )) { //log_error (_("Interface %s / %s is down.\n"), interface, itf->ifa_name); //log_error (_("Recheck uShare's configuration and try again !\n")); log_error (_("Interface %s / %s is up.\n"), interface, itf->ifa_name); freeifaddrs (itflist); return true; } itf = itf->ifa_next; } freeifaddrs (itf); #else int sock, i, n; struct ifconf ifc; struct ifreq ifr; char buff[8192]; if (!interface) return false; /* determine UDN according to MAC address */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); return false; } /* get list of available interfaces */ ifc.ifc_len = sizeof (buff); ifc.ifc_buf = buff; if (ioctl (sock, SIOCGIFCONF, &ifc) < 0) { perror ("ioctl"); close (sock); return false; } n = ifc.ifc_len / sizeof (struct ifreq); for (i = n - 1 ; i >= 0 ; i--) { ifr = ifc.ifc_req[i]; if (strncmp (ifr.ifr_name, interface, IFNAMSIZ)) continue; if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) { perror ("ioctl"); close (sock); return false; } if (!(ifr.ifr_flags & IFF_UP)) { /* interface is down */ log_error (_("Interface1 %s is down.\n"), interface); log_error (_("Recheck uShare's configuration and try again !\n")); close (sock); return false; } /* found right interface */ close (sock); return true; } close (sock); #endif log_error (_("Can't find interface %s.\n"),interface); log_error (_("Recheck uShare's configuration and try again !\n")); return false; } static char * create_udn (char *interface) { int sock = -1; char *buf; unsigned char *ptr; #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__)) int mib[6]; size_t len; struct if_msghdr *ifm; struct sockaddr_dl *sdl; #else /* Linux */ struct ifreq ifr; #endif if (!interface) return NULL; #if (defined(BSD) || defined(__FreeBSD__) || defined(__APPLE__)) mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; mib[3] = AF_LINK; mib[4] = NET_RT_IFLIST; mib[5] = if_nametoindex (interface); if (mib[5] == 0) { perror ("if_nametoindex"); return NULL; } if (sysctl (mib, 6, NULL, &len, NULL, 0) < 0) { perror ("sysctl"); return NULL; } buf = (char*)malloc (len); if (sysctl (mib, 6, buf, &len, NULL, 0) < 0) { perror ("sysctl"); return NULL; } ifm = (struct if_msghdr *) buf; sdl = (struct sockaddr_dl*) (ifm + 1); ptr = (unsigned char *) LLADDR (sdl); #else /* Linux */ /* determine UDN according to MAC address */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); return NULL; } strcpy (ifr.ifr_name, interface); strcpy (ifr.ifr_hwaddr.sa_data, ""); if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0) { perror ("ioctl"); return NULL; } buf = (char *) malloc (64 * sizeof (char)); memset (buf, 0, 64); ptr = (unsigned char *) ifr.ifr_hwaddr.sa_data; #endif /* (defined(BSD) || defined(__FreeBSD__)) */ snprintf (buf, 64, "%s-%02x%02x%02x%02x%02x%02x", DEFAULT_UUID, (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)); if (sock) close (sock); return buf; } static char * get_iface_address (char *interface) { int sock; uint32_t ip; struct ifreq ifr; char *val; if (!interface) return NULL; /* determine UDN according to MAC address */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); return NULL; } strcpy (ifr.ifr_name, interface); ifr.ifr_addr.sa_family = AF_INET; if (ioctl (sock, SIOCGIFADDR, &ifr) < 0) { perror ("ioctl"); close (sock); return NULL; } val = (char *) malloc (16 * sizeof (char)); ip = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr; ip = ntohl (ip); sprintf (val, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF); close (sock); return val; } static int restart_upnp (struct ushare_t *ut) { finish_upnp (ut); if (ut->udn) free (ut->udn); ut->udn = create_udn (ut->interface); if (!ut->udn) return -1; if (ut->ip) free (ut->ip); ut->ip = get_iface_address (ut->interface); if (!ut->ip) return -1; return (init_upnp (ut)); } static void UPnPBreak (int s __attribute__ ((unused))) { ushare_signal_exit (); } static void reload_config (int s __attribute__ ((unused))) { struct ushare_t *ut2; bool reload = false; log_info (_("Reloading configuration...\n")); ut2 = ushare_new (ut->argc, ut->argv); if (!ut || !ut2) return; /* Parse args before cfg file, as we may override the default file */ if (parse_command_line (ut2) < 0 || parse_config_file (ut2) < 0) { ushare_free (ut2); return; } if (ut2->xbox360) { char *name; name = (char*)malloc (strlen (XBOX_MODEL_NAME) + strlen (ut2->model_name) + 4); sprintf (name, "%s (%s)", XBOX_MODEL_NAME, ut2->model_name); free (ut2->model_name); ut2->model_name = strdup (name); free (name); ut2->starting_id = STARTING_ENTRY_ID_XBOX360; } if (ut->name && strcmp (ut->name, ut2->name)) { free (ut->name); ut->name = ut2->name; ut2->name = NULL; reload = true; } if (ut->interface && strcmp (ut->interface, ut2->interface)) { if (!has_iface (ut2->interface)) { ushare_free (ut2); raise (SIGINT); } else { free (ut->interface); ut->interface = ut2->interface; ut2->interface = NULL; reload = true; } } if (ut->port != ut2->port) { ut->port = ut2->port; reload = true; } if (reload) { if (restart_upnp (ut) < 0) { ushare_free (ut2); raise (SIGINT); } } if (ut->contentlist) content_free (ut->contentlist); ut->contentlist = ut2->contentlist; ut2->contentlist = NULL; ushare_free (ut2); if (ut->contentlist) { free_metadata_list (ut); build_metadata_list (ut); } else { log_error (_("Error: no content directory to be shared.\n")); raise (SIGINT); } } void display_headers (void) { printf (_("%s (version %s), Internet UPnP A/V and DLNA Media Server.\n"), PACKAGE_NAME, VERSION); printf (_("John Sullivan (C) 2025, Dynamic Processing Systems LLC.\n")); printf (_("based on:\n")); printf (_("Benjamin Zores (C) 2005-2007, for GeeXboX Team.\n")); printf (_("See https://buuna.dwanta.com/ for more.\n")); } inline static void setup_i18n(void) { #ifdef CONFIG_NLS #ifdef HAVE_SETLOCALE setlocale (LC_ALL, ""); #endif #if (!defined(BSD) && !defined(__FreeBSD__)) bindtextdomain (PACKAGE, LOCALEDIR); #endif textdomain (PACKAGE); #endif } #define SHUTDOWN_MSG _("Server is shutting down: other clients will be notified soon, Bye bye ...\n") static void ushare_kill (ctrl_telnet_client *client, int argc __attribute__((unused)), char **argv __attribute__((unused))) { if (ut->use_telnet) { ctrl_telnet_client_send (client, SHUTDOWN_MSG); client->exiting = true; } ushare_signal_exit (); } #ifdef USE_BUNNY /* int handleCommand( struct ushare_t* ut, DssObject& o ) { int errorAddress = 0; logger.error("handleCommand ip is " + string(ut->ip)); if( pthread_mutex_lock( &o.server->controlMutex ) != 0 ) { logger.error( "ERROR: failed to lock mutex" ); g_quit = true; return -1; } //typedef multimap::const_iterator I2; //for( I2 i = _dpsServer->localidComm.begin(); i != _dpsServer->localidComm.end(); ++i ) { //logger.error("list is " + i->first); //} multimap::const_iterator I = o.server->localidComm.find( o.getLocalId() ); int numUpdateFrames = 0; bool conflict = false; while( I != o.server->localidComm.end() ) { logger.error("found command " + I->second.op + " chan " + I->second.channel + " val " + I->second.val); if( I->second.op == "update" ) { } ++I; } if( pthread_mutex_unlock( &o.server->controlMutex ) != 0 ) { //logger.error( "ERROR: failed to unlock mutex" ); g_quit = true; } return 0; } */ int ushare_main (DssObject &o) { char** argv = NULL; // {"bunny_ushare", "-b" }; int argc = 0; #else int main (int argc, char **argv) { #endif setup_i18n (); setup_iconv (); ut = ushare_new (argc, argv); if (!ut) return EXIT_FAILURE; #ifdef USE_BUNNY if( o.server != NULL ) { map::const_iterator I = o.server->configMap.find("loglevel"); if( I != o.server->configMap.end() ) { if( I->second != "0" ) ut->verbose = true; } I = o.server->configMap.find("use_cache"); if( I != o.server->configMap.end() ) { if( I->second == "no" ) ut->use_cache = false; } } string p = string(INSTALLDIR) + string("/conf/ushare.conf"); ut->cfg_file = strdup (p.c_str()); #endif /* Parse args before cfg file, as we may override the default file */ if (parse_command_line (ut) < 0) { ushare_free (ut); return EXIT_SUCCESS; } if (parse_config_file (ut) < 0) { /* fprintf here, because syslog not yet ready */ fprintf (stderr, _("Warning: can't parse file \"%s\".\n"), ut->cfg_file ? ut->cfg_file : SYSCONFDIR "/" USHARE_CONFIG_FILE); } #ifdef USE_BUNNY ut->bunny = true; //ut->verbose = false; ut->verbose = true; ut->xbox360 = true; ut->dssObj = &o; ut->use_cache = true; #endif if (ut->daemon) { /* starting syslog feature as soon as possible */ start_log (); } if (ut->xbox360) { char *name; name = (char*)malloc (strlen (XBOX_MODEL_NAME) + strlen (ut->model_name) + 4); sprintf (name, "%s (%s)", XBOX_MODEL_NAME, ut->model_name); free (ut->model_name); ut->model_name = strdup (name); free (name); ut->starting_id = STARTING_ENTRY_ID_XBOX360; } if (!ut->contentlist) { log_error (_("Error: no content directory to be shared.\n")); ushare_free (ut); return EXIT_FAILURE; } if (!has_iface (ut->interface)) { ushare_free (ut); return EXIT_FAILURE; } ut->udn = create_udn (ut->interface); if (!ut->udn) { ushare_free (ut); return EXIT_FAILURE; } ut->ip = get_iface_address (ut->interface); if (!ut->ip) { ushare_free (ut); return EXIT_FAILURE; } if (ut->daemon) { int err; err = daemon (0, 0); if (err == -1) { log_error (_("Error: failed to daemonize program : %s\n"), strerror (err)); ushare_free (ut); return EXIT_FAILURE; } } else { display_headers (); } signal (SIGINT, UPnPBreak); signal (SIGHUP, reload_config); if (ut->use_telnet) { if (ctrl_telnet_start (ut->telnet_port) < 0) { ushare_free (ut); return EXIT_FAILURE; } ctrl_telnet_register ("kill", ushare_kill, _("Terminates the uShare server")); } if (init_upnp (ut) < 0) { finish_upnp (ut); ushare_free (ut); return EXIT_FAILURE; } /* Rescans library every 30 seconds until ready to terminate. */ if( ut->bunny ) { build_bunny_metadata_list(ut); while (!ut->term && !sleep(10)) { //free_bunny_metadata_list (ut); //build_bunny_metadata_list (ut); /* time_t timeoutns = 25000000; time_t timeout = 0; struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = timeoutns - 10; nanosleep(&ts, NULL); int rc = o.server->sems.semGet( o.semNum, o.offset, 0, 10); if( rc == 0 ) { // should probably return a 1 here logger.error("received a signal, doing commands"); rc = handleCommand( ut, o ); } */ } } else { build_metadata_list(ut); while (!ut->term && !sleep(30)) { free_metadata_list (ut); build_metadata_list (ut); } } if (ut->use_telnet) ctrl_telnet_stop (); finish_upnp (ut); free_metadata_list (ut); ushare_free (ut); finish_iconv (); return EXIT_SUCCESS; }