int main(const int argc, const char *argv[]) { event_set_log_callback(write_to_file_cb); event_enable_debug_mode(); //log_level(LOG_DEBUG); log_fileline(LOG_FILELINE_ON); log_level(LOG_WARN); server_t *server = server_init(DEFAULT_PORT); if(server == NULL) { log_err(__FILE__, __LINE__, "Cannot init server."); exit(-1); } int power = 10; server->service_idx = service_index_init(power); char *str = NULL; str = calloc(sizeof(char), 5); memcpy(str, "aaaa", 4); service_t *aaaa = service_init(str); aaaa = service_add(server->service_idx, power, aaaa); server->service_first = aaaa; server->service_last = aaaa; server->num_services++; str = calloc(sizeof(char), 5); memcpy(str, "bbbb", 4); service_t *bbbb = service_init(str); bbbb = service_add(server->service_idx, power, bbbb); aaaa->all_next = bbbb; server->service_last = bbbb; server->num_services++; str = calloc(sizeof(char), 5); memcpy(str, "cccc", 4); service_t *cccc = service_init(str); cccc = service_add(server->service_idx, power, cccc); bbbb->all_next = cccc; server->service_last = cccc; server->num_services++; server_event_run(server); return 0; }
bool master_udp::run_alone(const char* addrs, const char* path /* = NULL */, unsigned int count /* = 1 */) { // 每个进程只能有一个实例在运行 acl_assert(has_called == false); has_called = true; daemon_mode_ = false; __count_limit = count; acl_assert(addrs && *addrs); #ifdef ACL_WINDOWS acl_init(); #endif ACL_EVENT* eventp = acl_event_new_select(1, 0); set_event(eventp); // 设置基类的事件句柄 ACL_ARGV* tokens = acl_argv_split(addrs, ";,| \t"); ACL_ITER iter; acl_foreach(iter, tokens) { const char* addr = (const char*) iter.data; ACL_VSTREAM* sstream = acl_vstream_bind(addr, 0); if (sstream == NULL) { logger_error("bind %s error %s", addr, last_serror()); close_sstreams(); acl_event_free(eventp); acl_argv_free(tokens); return false; } acl_event_enable_read(eventp, sstream, 0, read_callback, sstream); socket_stream* ss = NEW socket_stream(); if (ss->open(sstream) == false) logger_fatal("open stream error!"); sstream->context = ss; sstreams_.push_back(ss); } acl_argv_free(tokens); // 初始化配置参数 conf_.load(path); service_pre_jail(NULL, NULL); service_init(NULL, NULL); while (!__stop) acl_event_loop(eventp); service_exit(NULL, NULL); // 必须在调用 acl_event_free 前调用 close_sstreams,因为在关闭 // 网络流对象时依然有对 ACL_EVENT 引擎的使用 close_sstreams(); acl_event_free(eventp); return true; }
int pool_set(pool_proc* dpool, pool_mutex* dpool_mutex) { pid_t cpid; for ( int i = 0; i < M; i++ ) { cpid = fork(); $( cpid < 0, "fork", "" ); if (cpid == 0) { while(1) { service_accept(dpool, dpool_mutex); service_exchange(dpool, dpool_mutex); service_done(dpool, dpool_mutex); } } else { dpool_mutex->processing_n++; service_init(cpid, dpool, dpool_mutex); } } return 0; }
void master_trigger::run_alone(const char* path /* = NULL */, int count /* = 1 */, int interval /* = 1 */) { // 每个进程只能有一个实例在运行 acl_assert(has_called == false); has_called = true; daemon_mode_ = false; #ifdef WIN32 acl_init(); #endif if (interval <= 0) interval = 1; // 初始化配置参数 conf_.load(path); service_pre_jail(NULL, NULL); service_init(NULL, NULL); int i = 0; while (true) { sleep(interval); service_main(NULL, 0, NULL, NULL); if (count > 0 && ++i >= count) break; } service_exit(NULL, NULL); }
/**@brief Function for application main entry. */ int main(void) { bool erase_bonds; uint32_t err_code; // Initialize. app_trace_init(); timers_init(); uart_init(); buttons_leds_init(&erase_bonds); ble_stack_init(); APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE); printf("BLE ANCS\n"); device_manager_init(erase_bonds); db_discovery_init(); scheduler_init(); gap_params_init(); service_init(); advertising_init(); conn_params_init(); // Start execution. err_code = ble_advertising_start(BLE_ADV_MODE_FAST); APP_ERROR_CHECK(err_code); // Enter main loop. for (;;) { app_sched_execute(); power_manage(); } }
/** * The main function for the service. * Called by the services API when starting on windows in background. * Arguments could have been present in the string 'path'. * @param argc: nr args * @param argv: arg text. */ static void service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv)) { struct cfg* cfg = NULL; struct svr* svr = NULL; service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)hdlr); if(!service_status_handle) { reportev("Could not RegisterServiceCtrlHandler"); return; } service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwServiceSpecificExitCode = 0; /* we are now starting up */ report_status(SERVICE_START_PENDING, NO_ERROR, 3000); if(!service_init(&svr, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } /* event that gets signalled when we want to quit */ service_stop_event = WSACreateEvent(); if(service_stop_event == WSA_INVALID_EVENT) { log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError())); reportev("Could not WSACreateEvent"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } if(!WSAResetEvent(service_stop_event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } wsvc_setup_worker(svr->base); /* SetServiceStatus SERVICE_RUNNING;*/ report_status(SERVICE_RUNNING, NO_ERROR, 0); verbose(VERB_QUERY, "winservice - init complete"); /* register DHCP hook and perform first sweep */ netlist_start(svr); /* daemon performs work */ svr_service(svr); /* exit */ verbose(VERB_ALGO, "winservice - cleanup."); report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); netlist_stop(); wsvc_desetup_worker(); service_deinit(svr, cfg); free(service_cfgfile); if(service_stop_event) (void)WSACloseEvent(service_stop_event); verbose(VERB_QUERY, "winservice - full stop"); report_status(SERVICE_STOPPED, NO_ERROR, 0); }
bool master_aio::run_alone(const char* addrs, const char* path /* = NULL */, aio_handle_type ht /* = ENGINE_SELECT */) { acl_assert(__handle == NULL); daemon_mode_ = false; #ifdef WIN32 acl_init(); #endif std::vector<aio_listen_stream*> sstreams; ACL_ARGV* tokens = acl_argv_split(addrs, ";,| \t"); ACL_ITER iter; // 初始化配置参数 conf_.load(path); __handle = NEW aio_handle(ht); ACL_AIO* aio = __handle->get_handle(); acl_assert(aio); ACL_EVENT* eventp = acl_aio_event(aio); set_event(eventp); // 设置基类的事件句柄 acl_foreach(iter, tokens) { const char* addr = (const char*) iter.data; aio_listen_stream* sstream = NEW aio_listen_stream(__handle); // 监听指定的地址 if (sstream->open(addr) == false) { logger_error("listen %s error: %s", addr, last_serror()); close_all_listener(sstreams); // XXX: 为了保证能关闭监听流,应在此处再 check 一下 __handle->check(); acl_argv_free(tokens); return (false); } sstream->add_accept_callback(this); } acl_argv_free(tokens); service_pre_jail(NULL); service_init(NULL); while (true) { // 如果返回 false 则表示不再继续,需要退出 if (__handle->check() == false) { logger("aio_server stop now ..."); break; } } close_all_listener(sstreams); __handle->check(); service_exit(NULL); return true; }
void boot_64(uint32_t magic, uint32_t multiboot) { // checking multiboot magic variable. VGA_AT(0,0) = VGA_ENTRY('H', WHITE_ON_BLACK); if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { VGA_AT(0,1) = VGA_ENTRY('!', WHITE_ON_BLACK); kernel_panic(); } // copying multiboot data. VGA_AT(0,1) = VGA_ENTRY('E', WHITE_ON_BLACK); multiboot_info_t *info = (multiboot_info_t *)kernel_p2v((uintptr_t)multiboot); switch (multiboot_copy(info)) { case MULTIBOOT_TOO_MANY_MEMORY_MAPS: VGA_AT(0,2) = VGA_ENTRY('?', WHITE_ON_BLACK); kernel_panic(); case MULTIBOOT_TOO_MANY_MODULES: VGA_AT(0,2) = VGA_ENTRY('?', WHITE_ON_BLACK); kernel_panic(); case MULTIBOOT_TOO_MANY_ELF_HEADERS: VGA_AT(0,2) = VGA_ENTRY('.', WHITE_ON_BLACK); kernel_panic(); } // we no longer need the original memory map at zero address. VGA_AT(0,2) = VGA_ENTRY('L', WHITE_ON_BLACK); page_set_pdpt(0, 0, 0); page_invalidate_all(); // initialize page allocators. VGA_AT(0,3) = VGA_ENTRY('L', WHITE_ON_BLACK); lomem_init(); himem_init(); // initialize CPUs. VGA_AT(0,4) = VGA_ENTRY('B', WHITE_ON_BLACK); cpu_enable_features(); cpu_init(); service_init(); gdt_init(); // adds per-cpu TSS into GDT. tss_update(); // initialize interrupt handling. VGA_AT(0,5) = VGA_ENTRY('E', WHITE_ON_BLACK); pic_init(); idt_init(); // kick-start the core service. VGA_AT(0,6) = VGA_ENTRY('N', WHITE_ON_BLACK); kernel_start_core(); // start scheduler and do stuff. VGA_AT(0,7) = VGA_ENTRY('D', WHITE_ON_BLACK); kernel_main(); }
bool master_proc::run_alone(const char* addrs, const char* path /* = NULL */, int count /* = 1 */) { // 每个进程只能有一个实例在运行 acl_assert(has_called == false); has_called = true; daemon_mode_ = false; __count_limit = count; acl_assert(addrs && *addrs); #ifdef ACL_WINDOWS acl_cpp_init(); #endif ACL_EVENT* eventp = acl_event_new_select(1, 0); set_event(eventp); // 调用基类方法设置事件引擎句柄 std::vector<ACL_VSTREAM*> sstreams; ACL_ARGV* tokens = acl_argv_split(addrs, ";,| \t"); ACL_ITER iter; acl_foreach(iter, tokens) { const char* addr = (const char*) iter.data; ACL_VSTREAM* sstream = acl_vstream_listen(addr, 128); if (sstream == NULL) { logger_error("listen %s error %s", addr, last_serror()); close_all_listener(sstreams); acl_argv_free(tokens); return false; } service_on_listen(sstream); acl_event_enable_listen(eventp, sstream, 0, listen_callback, sstream); sstreams.push_back(sstream); } acl_argv_free(tokens); // 初始化配置参数 conf_.load(path); service_pre_jail(NULL, NULL); service_init(NULL, NULL); while (!__stop) acl_event_loop(eventp); close_all_listener(sstreams); acl_event_free(eventp); service_exit(NULL, NULL); return true; }
/* Initialize from ini file */ int sbase_initialize(SBASE *sbase, char *conf) { char *p = NULL, *cacert_file = NULL, *privkey_file = NULL; if((dict = iniparser_new(conf)) == NULL) { fprintf(stderr, "Initializing conf:%s failed, %s\n", conf, strerror(errno)); _exit(-1); } /* SBASE */ sbase->nchilds = iniparser_getint(dict, "SBASE:nchilds", 0); sbase->connections_limit = iniparser_getint(dict, "SBASE:connections_limit", SB_CONN_MAX); sbase->usec_sleep = iniparser_getint(dict, "SBASE:usec_sleep", SB_USEC_SLEEP); sbase->set_log(sbase, iniparser_getstr(dict, "SBASE:logfile")); sbase->set_log_level(sbase, iniparser_getint(dict, "SBASE:log_level", 2)); sbase->set_evlog(sbase, iniparser_getstr(dict, "SBASE:evlogfile")); /* NOWD */ if((nowd = service_init()) == NULL) { fprintf(stderr, "Initialize service failed, %s", strerror(errno)); _exit(-1); } nowd->family = iniparser_getint(dict, "NOWD:inet_family", AF_INET); nowd->sock_type = iniparser_getint(dict, "NOWD:socket_type", SOCK_STREAM); nowd->ip = iniparser_getstr(dict, "NOWD:service_ip"); nowd->port = iniparser_getint(dict, "NOWD:service_port", 80); nowd->working_mode = iniparser_getint(dict, "NOWD:working_mode", WORKING_PROC); nowd->service_type = iniparser_getint(dict, "NOWD:service_type", S_SERVICE); nowd->service_name = iniparser_getstr(dict, "NOWD:service_name"); nowd->nprocthreads = iniparser_getint(dict, "NOWD:nprocthreads", 8); nowd->niodaemons = iniparser_getint(dict, "NOWD:niodaemons", 1); nowd->ndaemons = iniparser_getint(dict, "NOWD:ndaemons", 0); nowd->session.packet_type=iniparser_getint(dict, "NOWD:packet_type", PACKET_PROXY); nowd->session.buffer_size = iniparser_getint(dict, "NOWD:buffer_size", SB_BUF_SIZE); nowd->session.welcome_handler = &nowd_welcome_handler; nowd->session.exchange_handler = &nowd_exchange_handler; cacert_file = iniparser_getstr(dict, "NOWD:cacert_file"); privkey_file = iniparser_getstr(dict, "NOWD:privkey_file"); if(cacert_file && privkey_file && iniparser_getint(dict, "NOWD:is_use_SSL", 0)) { nowd->is_use_SSL = 1; nowd->cacert_file = cacert_file; nowd->privkey_file = privkey_file; } if((p = iniparser_getstr(dict, "NOWD:logfile"))) { nowd->set_log(nowd, p); nowd->set_log_level(nowd, iniparser_getint(dict, "NOWD:log_level", 0)); } /* server */ fprintf(stdout, "Parsing for server...\n"); return sbase->add_service(sbase, nowd); }
static void example_app_window_init (ExampleAppWindow *win) { ExampleAppWindowPrivate *priv; GtkBuilder *builder; GMenuModel *menu; GAction *action; priv = example_app_window_get_instance_private (win); gtk_widget_init_template (GTK_WIDGET (win)); priv->settings = g_settings_new ("com.lonelycactus.exampleapp"); g_settings_bind (priv->settings, "transition", priv->stack, "transition-type", G_SETTINGS_BIND_DEFAULT); g_settings_bind (priv->settings, "show-words", priv->sidebar, "reveal-child", G_SETTINGS_BIND_DEFAULT); g_object_bind_property (priv->search, "active", priv->searchbar, "search-mode-enabled", G_BINDING_BIDIRECTIONAL); g_signal_connect (priv->connect, "toggled", G_CALLBACK (toggle_server), win); g_signal_connect (priv->sidebar, "notify::reveal-child", G_CALLBACK (words_changed), win); builder = gtk_builder_new_from_resource ("/com/lonelycactus/exampleapp/gears-menu.ui"); menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu")); gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (priv->gears), menu); g_object_unref (builder); action = g_settings_create_action (priv->settings, "show-words"); g_action_map_add_action (G_ACTION_MAP (win), action); g_object_unref (action); action = (GAction*) g_property_action_new ("show-lines", priv->lines, "visible"); g_action_map_add_action (G_ACTION_MAP (win), action); g_object_unref (action); g_object_bind_property (priv->lines, "visible", priv->lines_label, "visible", G_BINDING_DEFAULT); service_init(); service_start_accepting_new_connections(); g_object_set (gtk_settings_get_default (), "gtk-shell-shows-app-menu", FALSE, NULL); gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE); }
int main(int argc, char **argv) { /* locale */ setlocale(LC_ALL, "C"); /* signal */ signal(SIGTERM, &lhttpd_stop); signal(SIGINT, &lhttpd_stop); signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); setrlimiter("RLIMIT_NOFILE", RLIMIT_NOFILE, 10240); if((sbase = sbase_init()) == NULL) { exit(EXIT_FAILURE); } if((lhttpd = service_init()) == NULL) { fprintf(stderr, "Initialize service failed, %s", strerror(errno)); _exit(-1); } lhttpd->family = AF_INET; lhttpd->sock_type = SOCK_STREAM; lhttpd->ip = "0.0.0.0"; lhttpd->port = 2080; lhttpd->use_cond_wait = 1; lhttpd->flag = SB_USE_COND|SB_USE_OUTDAEMON; lhttpd->working_mode = WORKING_THREAD; lhttpd->service_type = S_SERVICE; lhttpd->service_name = "lhttpd"; lhttpd->nprocthreads = 8; lhttpd->niodaemons = 2; lhttpd->session.packet_type= PACKET_DELIMITER; lhttpd->session.packet_delimiter = "\r\n\r\n"; lhttpd->session.packet_delimiter_length = strlen(lhttpd->session.packet_delimiter); lhttpd->session.buffer_size = SB_BUF_SIZE; lhttpd->session.packet_handler = &lhttpd_packet_handler; lhttpd->session.timeout_handler = &lhttpd_timeout_handler; lhttpd->set_log(lhttpd, "/tmp/lhttpd.log"); lhttpd->set_log_level(lhttpd, 2); httpd_home = "/data/www"; if(sbase->add_service(sbase, lhttpd) != 0) { fprintf(stderr, "add service lhttpd failed, %s\r\n", strerror(errno)); _exit(-1); } fprintf(stdout, "Initialized successed\n"); sbase->running(sbase, 0); //sbase->running(sbase, 60000000); sbase->stop(sbase); sbase->clean(sbase); return 0; }
/** * \brief I think of main as providing initialization and BLE event handling. One of the event handlers is used by the LBL's service and is defined * in the service_init() function. service_init() calls into the LBL's BLE service's initialization code which identifies the UUIDs of the LBL service. * \note Call service_init BEFORE advertising_init() * The BLE event dispatcher (ble_evt_dispatch()) calls the LBL's BLE event dispatcher. Communications with a client is through the client read/writing to characteristics. * \note I assume the power_manage() function does a "good job" interacting with the SoftDevice stack to minimize the amount of power used up by the LBL. I don't know how to fine tune * power management at this time. I use examples from the nRF51 SDK as a crutch, assuming the code for most of main functionality is "cookie cutter" across examples and the Nordic engineers that * write the examples realizes example code would be copy/pasted into our stuff. * @return while main is defined as an int, nothing is really returned. */ int main(void) { //call flash_init() before initializing service.. the ble_lbl_service uses flash to access pH4 and 7 calibration info.... (wow - too many dependencies!) //initialize pstorage() - the way i'll read/write from flash. POR is to use flash to store the calibration info for pH 4 and pH 7.. //Note in the S110 Softdevice documentation for pstorage, there is a note: // For implementation of interface included in the example, SoftDevice should be enabled and scheduler (if used) should be initialized prior to initializing this module. // ladybug_flash_init(); //a good part of this is "cookie cutter" from the nRF51 SDK...my-o-my there is a lot of code for BLE (within SoftDevice) and once SoftDevice is initialized - unfortunately - there is no longer source code debugging. ble_stack_init(); // The app timers rely on the BLE stack being initialized. This means app timer initialization must happen after BLE initialization. timers_init(); // (pstorage api access to) flash and the app timer used within the read/write flash functions require BLE and timers init first. ladybug_flash_init(); // The device name is needed as a GAP parameter. This is the first time a flash action (flash read) happens which means BLE and app timer init must happen first. char *p_deviceName; ladybug_get_device_name(&p_deviceName); SEGGER_RTT_printf(0,"Device name: %s \n",p_deviceName); SEGGER_RTT_printf(0,"String length: %d\n",strlen(p_deviceName)); gap_params_init(p_deviceName); //call service_init() before calling advertising_init()...service_init() calls into the LBL's BLE initialization code (where the LBL peripheral service and characteristics are defined) service_init(); advertising_init(); conn_params_init(); sec_params_init(); advertising_start(); // Enter main loop for (;;) { //Lazy write of values stored in flash //writing can get messed up if it is done inline with other BLE/sensing activity, and there is no rush. storeCalibrationValues_t *p_storeCalibrationValues; if (true == ladybug_there_are_calibration_values_to_write(&p_storeCalibrationValues)){ SEGGER_RTT_printf(0,"Writing calibration values to flash. Number of bytes: %d\n",sizeof(storeCalibrationValues_t)); ladybug_flash_write(calibrationValues,(uint8_t *)p_storeCalibrationValues,sizeof(storeCalibrationValues_t),did_flash_write); } storePlantInfo_t *p_storePlantInfo; if (true == ladybug_there_are_plantInfo_values_to_write(&p_storePlantInfo)){ SEGGER_RTT_WriteString(0,"...Writing plantInfo values to flash\n"); ladybug_flash_write(plantInfo,(uint8_t *)p_storePlantInfo,sizeof(storePlantInfo_t),did_flash_write); } char *p_deviceName; if (true == ladybug_the_device_name_has_been_updated(&p_deviceName)){ SEGGER_RTT_WriteString(0,"Writing device name to flash\n"); ladybug_flash_write(deviceName,(uint8_t *)p_deviceName,DEVNAME_MAX_LEN,did_flash_write); } power_manage(); } }
static VOID WINAPI service_main(DWORD argc, LPTSTR *argv) { status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, control_handler); if (!status_handle) return; // Initialise status with common attributes. service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwServiceSpecificExitCode = 0; // Report initial status to the SCM. ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000); // Perform service-specific initialization and work. service_init(argc, argv); }
static QState Ble_initial(Ble* const me) { timers_init(); //nrf_log_init(); ble_stack_init(); uint8_t BSP_readButton(); uint8_t btn = BSP_readButton(); device_manager_init(btn); db_discovery_init(); //scheduler_init(); gap_params_init(); service_init(); advertising_init(); conn_params_init(); return Q_TRAN(&Ble_disconnected); }
int main(int argc, char **argv) { FILE *f=0; int i; do { f = fopen("c:/tmp/service_t", "w"); debug_init(DEBUG_INFO, debug_func_stdio, f); debug(DEBUG_INFO, ("service_t main argc=%d argv[0]=%s\n", argc, argv[0])) i = service_init(argc, argv, service_main_func); } while(0); if( f ) fclose(f); return i; }
static void service_test(void) { const char *addr = "127.0.0.1:8885"; ACL_VSTREAM *sstream = acl_vstream_listen(addr, 32), *client; int ret; assert(sstream != NULL); acl_xinetd_params_int_table(NULL, var_conf_int_tab); acl_xinetd_params_str_table(NULL, var_conf_str_tab); acl_xinetd_params_bool_table(NULL, var_conf_bool_tab); printf("listen %s ok\n", addr); service_init(NULL); while (1) { client = acl_vstream_accept(sstream, NULL, 0); if (client == NULL) { printf("accept error: %s\n", acl_last_serror()); break; } while (1) { if (acl_readable(ACL_VSTREAM_SOCK(client)) == 0) continue; ret = service_main(client, NULL); if (ret < 0) { acl_vstream_close(client); break; } if (ret > 0) break; } } service_exit(NULL); acl_vstream_close(sstream); }
int main(int argc, char *argv[]) { ACL_VSTREAM *sstream, *client; ACL_WORK_QUEUE* wq = acl_workq_create(100, 60, NULL, NULL); char ch, *addr = "127.0.0.1:8889"; char *regnum = "regnum"; while ((ch = getopt(argc, argv, "hs:f:")) > 0) { switch (ch) { default: case 'h': usage(argv[0]); exit (0); case 's': addr = acl_mystrdup(optarg); break; case 'f': regnum = optarg; break; } } var_cfg_cache_file = acl_mystrdup(regnum); acl_socket_init(); service_init(NULL); sstream = acl_vstream_listen(addr, 32); if (sstream == NULL) acl_msg_fatal("can't listen on addr(%s)", addr); printf("started, listen on %s ...\r\n", addr); while (1) { client = acl_vstream_accept(sstream, NULL, 0); acl_workq_add(wq, client_thread, 0, client); } exit (0); }
/** * Showtime main */ int main(int argc, char **argv) { struct timeval tv; const char *settingspath = NULL; const char *uiargs[16]; const char *argv0 = argc > 0 ? argv[0] : "showtime"; const char *forceview = NULL; int nuiargs = 0; int can_standby = 0; int can_poweroff = 0; int r; trace_level = TRACE_INFO; gettimeofday(&tv, NULL); srand(tv.tv_usec); arch_set_default_paths(argc, argv); /* We read options ourselfs since getopt() is broken on some (nintento wii) targets */ argv++; argc--; while(argc > 0) { if(!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) { printf("HTS Showtime %s\n" "Copyright (C) 2007-2010 Andreas Öman\n" "\n" "Usage: %s [options] [<url>]\n" "\n" " Options:\n" " -h, --help - This help text.\n" " -d - Enable debug output.\n" " --ffmpeglog - Print ffmpeg log messages.\n" " --with-standby - Enable system standby.\n" " --with-poweroff - Enable system power-off.\n" " -s <path> - Non-default Showtime settings path.\n" " --ui <ui> - Use specified user interface.\n" " -L <ip:host> - Send log messages to remote <ip:host>.\n" " --syslog - Send log messages to syslog.\n" #if ENABLE_STDIN " --stdin - Listen on stdin for events.\n" #endif " -v <view> - Use specific view for <url>.\n" " --cache <path> - Set path for cache [%s].\n" #if ENABLE_SERDEV " --serdev - Probe service ports for devices.\n" #endif "\n" " URL is any URL-type supported by Showtime, " "e.g., \"file:///...\"\n" "\n", htsversion_full, argv0, showtime_cache_path); exit(0); argc--; argv++; } else if(!strcmp(argv[0], "-d")) { trace_level++; argc -= 1; argv += 1; continue; } else if(!strcmp(argv[0], "--ffmpeglog")) { ffmpeglog = 1; argc -= 1; argv += 1; continue; } else if(!strcmp(argv[0], "--syslog")) { trace_to_syslog = 1; argc -= 1; argv += 1; continue; } else if(!strcmp(argv[0], "--stdin")) { listen_on_stdin = 1; argc -= 1; argv += 1; continue; #if ENABLE_SERDEV } else if(!strcmp(argv[0], "--serdev")) { enable_serdev = 1; argc -= 1; argv += 1; continue; #endif } else if(!strcmp(argv[0], "--with-standby")) { can_standby = 1; argc -= 1; argv += 1; continue; } else if(!strcmp(argv[0], "--with-poweroff")) { can_poweroff = 1; argc -= 1; argv += 1; continue; } else if(!strcmp(argv[0], "-s") && argc > 1) { settingspath = argv[1]; argc -= 2; argv += 2; continue; } else if(!strcmp(argv[0], "--ui") && argc > 1) { if(nuiargs < 16) uiargs[nuiargs++] = argv[1]; argc -= 2; argv += 2; continue; } else if(!strcmp(argv[0], "-L") && argc > 1) { showtime_logtarget = argv[1]; argc -= 2; argv += 2; continue; } else if (!strcmp(argv[0], "-v") && argc > 1) { forceview = argv[1]; argc -= 2; argv += 2; } else if (!strcmp(argv[0], "--cache") && argc > 1) { mystrset(&showtime_cache_path, argv[1]); argc -= 2; argv += 2; #ifdef __APPLE__ /* ignore -psn argument, process serial number */ } else if(!strncmp(argv[0], "-psn", 4)) { argc -= 1; argv += 1; continue; #endif } else break; } unicode_init(); /* Initialize property tree */ prop_init(); init_global_info(); /* Initiailize logging */ trace_init(); /* Callout framework */ callout_init(); /* Notification framework */ notifications_init(); /* Architecture specific init */ arch_init(); htsmsg_store_init(); /* Try to create cache path */ if(showtime_cache_path != NULL && (r = makedirs(showtime_cache_path)) != 0) { TRACE(TRACE_ERROR, "cache", "Unable to create cache path %s -- %s", showtime_cache_path, strerror(r)); showtime_cache_path = NULL; } /* Initializte blob cache */ blobcache_init(); /* Try to create settings path */ if(showtime_settings_path != NULL && (r = makedirs(showtime_settings_path)) != 0) { TRACE(TRACE_ERROR, "settings", "Unable to create settings path %s -- %s", showtime_settings_path, strerror(r)); showtime_settings_path = NULL; } /* Initialize keyring */ keyring_init(); /* Initialize settings */ settings_init(); /* Initialize libavcodec & libavformat */ av_lockmgr_register(fflockmgr); av_log_set_callback(fflog); av_register_all(); /* Freetype keymapper */ #if ENABLE_LIBFREETYPE freetype_init(); #endif /* Global keymapper */ keymapper_init(); /* Initialize media subsystem */ media_init(); /* Service handling */ service_init(); /* Initialize backend content handlers */ backend_init(); /* Initialize navigator */ nav_init(); /* Initialize audio subsystem */ audio_init(); /* Initialize bookmarks */ bookmarks_init(); /* Initialize plugin manager and load plugins */ plugins_init(); /* Internationalization */ i18n_init(); nav_open(NAV_HOME, NULL); /* Open initial page */ if(argc > 0) nav_open(argv[0], forceview); /* Various interprocess communication stuff (D-Bus on Linux, etc) */ ipc_init(); /* Service discovery. Must be after ipc_init() (d-bus and threads, etc) */ sd_init(); /* Initialize various external APIs */ api_init(); /* HTTP server and UPNP */ #if ENABLE_HTTPSERVER http_server_init(); upnp_init(); #endif /* */ runcontrol_init(can_standby, can_poweroff); TRACE(TRACE_DEBUG, "core", "Starting UI"); /* Initialize user interfaces */ ui_start(nuiargs, uiargs, argv0); finalize(); }
int main(int argc, char **argv) { int i; sigset_t set; #if ENABLE_MPEGTS uint32_t adapter_mask = 0; #endif int log_level = LOG_INFO; int log_options = TVHLOG_OPT_MILLIS | TVHLOG_OPT_STDERR | TVHLOG_OPT_SYSLOG; const char *log_debug = NULL, *log_trace = NULL; gid_t gid = -1; uid_t uid = -1; char buf[512]; FILE *pidfile = NULL; extern int dvb_bouquets_parse; main_tid = pthread_self(); /* Setup global mutexes */ pthread_mutex_init(&fork_lock, NULL); pthread_mutex_init(&global_lock, NULL); pthread_mutex_init(&tasklet_lock, NULL); pthread_mutex_init(&atomic_lock, NULL); pthread_cond_init(>imer_cond, NULL); pthread_cond_init(&tasklet_cond, NULL); TAILQ_INIT(&tasklets); /* Defaults */ tvheadend_webui_port = 9981; tvheadend_webroot = NULL; tvheadend_htsp_port = 9982; tvheadend_htsp_port_extra = 0; time(&dispatch_clock); /* Command line options */ int opt_help = 0, opt_version = 0, opt_fork = 0, opt_firstrun = 0, opt_stderr = 0, opt_syslog = 0, opt_nosyslog = 0, opt_uidebug = 0, opt_abort = 0, opt_noacl = 0, opt_fileline = 0, opt_threadid = 0, opt_libav = 0, opt_ipv6 = 0, opt_satip_rtsp = 0, #if ENABLE_TSFILE opt_tsfile_tuner = 0, #endif opt_dump = 0, opt_xspf = 0, opt_dbus = 0, opt_dbus_session = 0, opt_nobackup = 0, opt_nobat = 0; const char *opt_config = NULL, *opt_user = NULL, *opt_group = NULL, *opt_logpath = NULL, *opt_log_debug = NULL, *opt_log_trace = NULL, *opt_pidpath = "/var/run/tvheadend.pid", #if ENABLE_LINUXDVB *opt_dvb_adapters = NULL, #endif *opt_bindaddr = NULL, *opt_subscribe = NULL, *opt_user_agent = NULL; str_list_t opt_satip_xml = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) }; str_list_t opt_tsfile = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) }; cmdline_opt_t cmdline_opts[] = { { 0, NULL, N_("Generic Options"), OPT_BOOL, NULL }, { 'h', "help", N_("Show this page"), OPT_BOOL, &opt_help }, { 'v', "version", N_("Show version information"),OPT_BOOL, &opt_version }, { 0, NULL, N_("Service Configuration"), OPT_BOOL, NULL }, { 'c', "config", N_("Alternate config path"), OPT_STR, &opt_config }, { 'B', "nobackup", N_("Don't backup config tree at upgrade"), OPT_BOOL, &opt_nobackup }, { 'f', "fork", N_("Fork and run as daemon"), OPT_BOOL, &opt_fork }, { 'u', "user", N_("Run as user"), OPT_STR, &opt_user }, { 'g', "group", N_("Run as group"), OPT_STR, &opt_group }, { 'p', "pid", N_("Alternate pid path"), OPT_STR, &opt_pidpath }, { 'C', "firstrun", N_("If no user account exists then create one with\n" "no username and no password. Use with care as\n" "it will allow world-wide administrative access\n" "to your Tvheadend installation until you edit/create\n" "access-control from within the Tvheadend UI"), OPT_BOOL, &opt_firstrun }, #if ENABLE_DBUS_1 { 'U', "dbus", N_("Enable DBus"), OPT_BOOL, &opt_dbus }, { 'e', "dbus_session", N_("DBus - use the session message bus instead system one"), OPT_BOOL, &opt_dbus_session }, #endif #if ENABLE_LINUXDVB { 'a', "adapters", N_("Only use specified DVB adapters (comma separated)"), OPT_STR, &opt_dvb_adapters }, #endif #if ENABLE_SATIP_SERVER { 0, "satip_rtsp", N_("SAT>IP RTSP port number for server\n" "(default: -1 = disable, 0 = webconfig, standard port is 554)"), OPT_INT, &opt_satip_rtsp }, #endif #if ENABLE_SATIP_CLIENT { 0, "satip_xml", N_("URL with the SAT>IP server XML location"), OPT_STR_LIST, &opt_satip_xml }, #endif { 0, NULL, N_("Server Connectivity"), OPT_BOOL, NULL }, { '6', "ipv6", N_("Listen on IPv6"), OPT_BOOL, &opt_ipv6 }, { 'b', "bindaddr", N_("Specify bind address"), OPT_STR, &opt_bindaddr}, { 0, "http_port", N_("Specify alternative http port"), OPT_INT, &tvheadend_webui_port }, { 0, "http_root", N_("Specify alternative http webroot"), OPT_STR, &tvheadend_webroot }, { 0, "htsp_port", N_("Specify alternative htsp port"), OPT_INT, &tvheadend_htsp_port }, { 0, "htsp_port2", N_("Specify extra htsp port"), OPT_INT, &tvheadend_htsp_port_extra }, { 0, "useragent", N_("Specify User-Agent header for the http client"), OPT_STR, &opt_user_agent }, { 0, "xspf", N_("Use XSPF playlist instead of M3U"), OPT_BOOL, &opt_xspf }, { 0, NULL, N_("Debug Options"), OPT_BOOL, NULL }, { 'd', "stderr", N_("Enable debug on stderr"), OPT_BOOL, &opt_stderr }, { 's', "syslog", N_("Enable debug to syslog"), OPT_BOOL, &opt_syslog }, { 'S', "nosyslog", N_("Disable syslog (all msgs)"), OPT_BOOL, &opt_nosyslog }, { 'l', "logfile", N_("Enable debug to file"), OPT_STR, &opt_logpath }, { 0, "debug", N_("Enable debug subsystems"), OPT_STR, &opt_log_debug }, #if ENABLE_TRACE { 0, "trace", N_("Enable trace subsystems"), OPT_STR, &opt_log_trace }, #endif { 0, "fileline", N_("Add file and line numbers to debug"), OPT_BOOL, &opt_fileline }, { 0, "threadid", N_("Add the thread ID to debug"), OPT_BOOL, &opt_threadid }, #if ENABLE_LIBAV { 0, "libav", N_("More verbose libav log"), OPT_BOOL, &opt_libav }, #endif { 0, "uidebug", N_("Enable webUI debug (non-minified JS)"), OPT_BOOL, &opt_uidebug }, { 'A', "abort", N_("Immediately abort"), OPT_BOOL, &opt_abort }, { 'D', "dump", N_("Enable coredumps for daemon"), OPT_BOOL, &opt_dump }, { 0, "noacl", N_("Disable all access control checks"), OPT_BOOL, &opt_noacl }, { 0, "nobat", N_("Disable DVB bouquets"), OPT_BOOL, &opt_nobat }, { 'j', "join", N_("Subscribe to a service permanently"), OPT_STR, &opt_subscribe }, #if ENABLE_TSFILE || ENABLE_TSDEBUG { 0, NULL, N_("Testing options"), OPT_BOOL, NULL }, { 0, "tsfile_tuners", N_("Number of tsfile tuners"), OPT_INT, &opt_tsfile_tuner }, { 0, "tsfile", N_("tsfile input (mux file)"), OPT_STR_LIST, &opt_tsfile }, #endif #if ENABLE_TSDEBUG { 0, "tsdebug", N_("Output directory for tsdebug"), OPT_STR, &tvheadend_tsdebug }, #endif }; /* Get current directory */ tvheadend_cwd0 = dirname(tvh_strdupa(argv[0])); tvheadend_cwd = dirname(tvh_strdupa(tvheadend_cwd0)); /* Set locale */ setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); /* make sure the timezone is set */ tzset(); /* Process command line */ for (i = 1; i < argc; i++) { /* Find option */ cmdline_opt_t *opt = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]); if (!opt) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), _("invalid option specified [%s]"), argv[i]); /* Process */ if (opt->type == OPT_BOOL) *((int*)opt->param) = 1; else if (++i == argc) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), _("option %s requires a value"), opt->lopt); else if (opt->type == OPT_INT) *((int*)opt->param) = atoi(argv[i]); else if (opt->type == OPT_STR_LIST) { str_list_t *strl = opt->param; if (strl->num < strl->max) strl->str[strl->num++] = argv[i]; } else *((char**)opt->param) = argv[i]; /* Stop processing */ if (opt_help) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL); if (opt_version) show_version(argv[0]); } /* Additional cmdline processing */ if (opt_nobat) dvb_bouquets_parse = 0; #if ENABLE_LINUXDVB if (!opt_dvb_adapters) { adapter_mask = ~0; } else { char *p, *e; char *r = NULL; char *dvb_adapters = strdup(opt_dvb_adapters); adapter_mask = 0x0; p = strtok_r(dvb_adapters, ",", &r); while (p) { int a = strtol(p, &e, 10); if (*e != 0 || a < 0 || a > 31) { fprintf(stderr, _("Invalid adapter number '%s'\n"), p); free(dvb_adapters); return 1; } adapter_mask |= (1 << a); p = strtok_r(NULL, ",", &r); } free(dvb_adapters); if (!adapter_mask) { fprintf(stderr, "%s", _("No adapters specified!\n")); return 1; } } #endif if (tvheadend_webroot) { char *tmp; if (*tvheadend_webroot == '/') tmp = strdup(tvheadend_webroot); else { tmp = malloc(strlen(tvheadend_webroot)+2); *tmp = '/'; strcpy(tmp+1, tvheadend_webroot); } if (tmp[strlen(tmp)-1] == '/') tmp[strlen(tmp)-1] = '\0'; tvheadend_webroot = tmp; } tvheadend_webui_debug = opt_uidebug; /* Setup logging */ if (isatty(2)) log_options |= TVHLOG_OPT_DECORATE; if (opt_stderr || opt_syslog || opt_logpath) { if (!opt_log_trace && !opt_log_debug) log_debug = "all"; log_level = LOG_DEBUG; if (opt_stderr) log_options |= TVHLOG_OPT_DBG_STDERR; if (opt_syslog) log_options |= TVHLOG_OPT_DBG_SYSLOG; if (opt_logpath) log_options |= TVHLOG_OPT_DBG_FILE; } if (opt_nosyslog) log_options &= ~(TVHLOG_OPT_SYSLOG|TVHLOG_OPT_DBG_SYSLOG); if (opt_fileline) log_options |= TVHLOG_OPT_FILELINE; if (opt_threadid) log_options |= TVHLOG_OPT_THREAD; if (opt_libav) log_options |= TVHLOG_OPT_LIBAV; if (opt_log_trace) { log_level = LOG_TRACE; log_trace = opt_log_trace; } if (opt_log_debug) log_debug = opt_log_debug; tvhlog_init(log_level, log_options, opt_logpath); tvhlog_set_debug(log_debug); tvhlog_set_trace(log_trace); tvhinfo("main", "Log started"); signal(SIGPIPE, handle_sigpipe); // will be redundant later signal(SIGILL, handle_sigill); // see handler.. /* Set priviledges */ if(opt_fork || opt_group || opt_user) { const char *homedir; struct group *grp = getgrnam(opt_group ?: "video"); struct passwd *pw = opt_user ? getpwnam(opt_user) : NULL; if(grp != NULL) { gid = grp->gr_gid; } else { gid = 1; } if (pw != NULL) { if (getuid() != pw->pw_uid) { gid_t glist[16]; int gnum; gnum = get_user_groups(pw, glist, ARRAY_SIZE(glist)); if (gnum > 0 && setgroups(gnum, glist)) { char buf[256] = ""; int i; for (i = 0; i < gnum; i++) snprintf(buf + strlen(buf), sizeof(buf) - 1 - strlen(buf), ",%d", glist[i]); tvhlog(LOG_ALERT, "START", "setgroups(%s) failed, do you have permission?", buf+1); return 1; } } uid = pw->pw_uid; homedir = pw->pw_dir; setenv("HOME", homedir, 1); } else { uid = 1; } } uuid_init(); config_boot(opt_config, gid, uid); tcp_server_preinit(opt_ipv6); http_server_init(opt_bindaddr); // bind to ports only htsp_init(opt_bindaddr); // bind to ports only satip_server_init(opt_satip_rtsp); // bind to ports only if (opt_fork) pidfile = tvh_fopen(opt_pidpath, "w+"); if (gid != -1 && (getgid() != gid) && setgid(gid)) { tvhlog(LOG_ALERT, "START", "setgid(%d) failed, do you have permission?", gid); return 1; } if (uid != -1 && (getuid() != uid) && setuid(uid)) { tvhlog(LOG_ALERT, "START", "setuid(%d) failed, do you have permission?", uid); return 1; } /* Daemonise */ if(opt_fork) { if(daemon(0, 0)) { exit(2); } if(pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } /* Make dumpable */ if (opt_dump) { #ifdef PLATFORM_LINUX if (chdir("/tmp")) tvhwarn("START", "failed to change cwd to /tmp"); prctl(PR_SET_DUMPABLE, 1); #else tvhwarn("START", "Coredumps not implemented on your platform"); #endif } umask(0); } tvheadend_running = 1; /* Start log thread (must be done post fork) */ tvhlog_start(); /* Alter logging */ if (opt_fork) tvhlog_options &= ~TVHLOG_OPT_STDERR; if (!isatty(2)) tvhlog_options &= ~TVHLOG_OPT_DECORATE; /* Initialise clock */ pthread_mutex_lock(&global_lock); time(&dispatch_clock); /* Signal handling */ sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); trap_init(argv[0]); /* SSL library init */ OPENSSL_config(NULL); SSL_load_error_strings(); SSL_library_init(); /* Initialise configuration */ notify_init(); idnode_init(); spawn_init(); config_init(opt_nobackup == 0); /** * Initialize subsystems */ epg_in_load = 1; tvhthread_create(&tasklet_tid, NULL, tasklet_thread, NULL); dbus_server_init(opt_dbus, opt_dbus_session); intlconv_init(); api_init(); fsmonitor_init(); libav_init(); tvhtime_init(); profile_init(); imagecache_init(); http_client_init(opt_user_agent); esfilter_init(); bouquet_init(); service_init(); dvb_init(); #if ENABLE_MPEGTS mpegts_init(adapter_mask, &opt_satip_xml, &opt_tsfile, opt_tsfile_tuner); #endif channel_init(); bouquet_service_resolve(); subscription_init(); dvr_config_init(); access_init(opt_firstrun, opt_noacl); #if ENABLE_TIMESHIFT timeshift_init(); #endif tcp_server_init(); webui_init(opt_xspf); #if ENABLE_UPNP upnp_server_init(opt_bindaddr); #endif service_mapper_init(); descrambler_init(); epggrab_init(); epg_init(); dvr_init(); dbus_server_start(); http_server_register(); satip_server_register(); htsp_register(); if(opt_subscribe != NULL) subscription_dummy_join(opt_subscribe, 1); avahi_init(); bonjour_init(); epg_updated(); // cleanup now all prev ref's should have been created epg_in_load = 0; pthread_mutex_unlock(&global_lock); /** * Wait for SIGTERM / SIGINT, but only in this thread */ sigemptyset(&set); sigaddset(&set, SIGTERM); sigaddset(&set, SIGINT); signal(SIGTERM, doexit); signal(SIGINT, doexit); pthread_sigmask(SIG_UNBLOCK, &set, NULL); tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, " "running as PID:%d UID:%d GID:%d, CWD:%s CNF:%s", tvheadend_version, getpid(), getuid(), getgid(), getcwd(buf, sizeof(buf)), hts_settings_get_root()); if(opt_abort) abort(); mainloop(); #if ENABLE_DBUS_1 tvhftrace("main", dbus_server_done); #endif #if ENABLE_UPNP tvhftrace("main", upnp_server_done); #endif tvhftrace("main", satip_server_done); tvhftrace("main", htsp_done); tvhftrace("main", http_server_done); tvhftrace("main", webui_done); tvhftrace("main", fsmonitor_done); tvhftrace("main", http_client_done); tvhftrace("main", tcp_server_done); // Note: the locking is obviously a bit redundant, but without // we need to disable the gtimer_arm call in epg_save() pthread_mutex_lock(&global_lock); tvhftrace("main", epg_save); #if ENABLE_TIMESHIFT tvhftrace("main", timeshift_term); #endif pthread_mutex_unlock(&global_lock); tvhftrace("main", epggrab_done); #if ENABLE_MPEGTS tvhftrace("main", mpegts_done); #endif tvhftrace("main", descrambler_done); tvhftrace("main", service_mapper_done); tvhftrace("main", service_done); tvhftrace("main", channel_done); tvhftrace("main", bouquet_done); tvhftrace("main", dvr_done); tvhftrace("main", subscription_done); tvhftrace("main", access_done); tvhftrace("main", epg_done); tvhftrace("main", avahi_done); tvhftrace("main", bonjour_done); tvhftrace("main", imagecache_done); tvhftrace("main", lang_code_done); tvhftrace("main", api_done); tvhtrace("main", "tasklet enter"); pthread_cond_signal(&tasklet_cond); pthread_join(tasklet_tid, NULL); tvhtrace("main", "tasklet thread end"); tasklet_flush(); tvhtrace("main", "tasklet leave"); tvhftrace("main", hts_settings_done); tvhftrace("main", dvb_done); tvhftrace("main", lang_str_done); tvhftrace("main", esfilter_done); tvhftrace("main", profile_done); tvhftrace("main", intlconv_done); tvhftrace("main", urlparse_done); tvhftrace("main", idnode_done); tvhftrace("main", notify_done); tvhftrace("main", spawn_done); tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend"); tvhlog_end(); tvhftrace("main", config_done); if(opt_fork) unlink(opt_pidpath); #if ENABLE_TSFILE free(opt_tsfile.str); #endif free(opt_satip_xml.str); /* OpenSSL - welcome to the "cleanup" hell */ ENGINE_cleanup(); RAND_cleanup(); CRYPTO_cleanup_all_ex_data(); EVP_cleanup(); CONF_modules_free(); #ifndef OPENSSL_NO_COMP COMP_zlib_cleanup(); #endif ERR_remove_state(0); ERR_free_strings(); #ifndef OPENSSL_NO_COMP sk_SSL_COMP_free(SSL_COMP_get_compression_methods()); #endif /* end of OpenSSL cleanup code */ #if ENABLE_DBUS_1 extern void dbus_shutdown(void); if (opt_dbus) dbus_shutdown(); #endif return 0; } /** * */ void tvh_str_set(char **strp, const char *src) { free(*strp); *strp = src ? strdup(src) : NULL; } /** * */ int tvh_str_update(char **strp, const char *src) { if(src == NULL) return 0; free(*strp); *strp = strdup(src); return 1; } /** * */ void scopedunlock(pthread_mutex_t **mtxp) { pthread_mutex_unlock(*mtxp); }
int main(int argc, char **argv) { pid_t pid; char *url = NULL, *urllist = NULL, line[HTTP_BUF_SIZE], *s = NULL, *p = NULL, ch = 0; struct hostent *hent = NULL; int n = 0, log_level = 0, tcp_option = 0, socket_option = 0, niodaemons = 0, is_realtime = 0; /* get configure file */ while((ch = getopt(argc, argv, "vqpkdr:i:s:x:w:l:c:t:n:e:")) != -1) { switch(ch) { case 'c': concurrency = atoi(optarg); break; case 'n': ntasks = atoi(optarg); break; case 'l': urllist = optarg; break; case 'k': is_keepalive = 1; break; case 'w': if((n = atoi(optarg)) > 0) workers = n; break; case 'd': is_daemon = 1; break; case 'q': is_quiet = 1; break; case 'r': is_realtime = atoi(optarg); break; case 't': req_timeout = atoi(optarg); break; case 'p': is_post = 1; break; case 'x': tcp_option = atoi(optarg); break; case 's': socket_option = atoi(optarg); break; case 'i': niodaemons = atoi(optarg); break; case 'e': log_level = atoi(optarg); break; case 'v': is_verbosity = 1; break; case '?': url = argv[optind]; break; default: break; } } if(url == NULL && optind < argc) { //fprintf(stdout, "opt:%c optind:%d arg:%s\n", ch, optind, argv[optind]); url = argv[optind]; } //fprintf(stdout, "concurrency:%d nrequests:%d is_keepalive:%d is_daemon:%d\n", // concurrency, ntasks, is_keepalive, is_daemon); if(url == NULL) { fprintf(stderr, "Usage:%s [options] http(s)://host:port/path\n" "Options:\n\t-c concurrency\n\t-n requests\n" "\t-w worker threads\n\t-e log level\n\t-x tcp_option 1:tcp_nodelay\n" "\t-s socket_option 1:socket_linger\n\t-i iodaemons\n" "\t-t timeout (microseconds, default 1000000)\n" "\t-r is_realtime_thread 1:SCHED_FIFO 2:SCHED_RR\n" "\t-p is_POST\n\t-v is_verbosity\n\t-l urllist file\n" "\t-k is_keepalive\n\t-d is_daemon\n ", argv[0]); _exit(-1); } p = url; s = line; while(*p != '\0') { if(*p >= 'A' && *p <= 'Z') { *s++ = *p++ + 'a' - 'A'; } else if(*((unsigned char *)p) > 127 || *p == 0x20) { s += sprintf(s, "%%%02x", *((unsigned char *)p)); ++p; } else *s++ = *p++; } *s = '\0'; s = line; if(strncmp(s, "http://", 7) == 0) { s += 7; server_host = s; } else if(strncmp(s, "https://", 8) == 0) { s += 8; server_host = s; server_is_ssl = 1; } else goto invalid_url; while(*s != '\0' && *s != ':' && *s != '/')s++; if(*s == ':') { *s = '\0'; ++s; server_port = atoi(s); while(*s != '\0' && *s != '/')++s; } if(*s == '/') { *s = '\0'; ++s; server_url = s; } while(*s != '\0' && *s != '?')++s; if(*s == '?') { *s = '\0'; ++s; server_argv = s; } invalid_url: if(server_host == NULL || server_port <= 0) { fprintf(stderr, "Invalid url:%s, url must be http://host:port/path?argv " " or https://host:port/path?argv\n", url); _exit(-1); } if(urllist) fp = fopen(urllist, "rd"); if(is_post) { p = request; p += sprintf(p, "POST /%s HTTP/1.1\r\n", server_url); p += sprintf(p, "Host: %s:%d\r\n", server_host, server_port); if(is_keepalive) p += sprintf(p, "Connection: Keep-Alive\r\n"); p += sprintf(p, "Content-Length: %d\r\n\r\n", (int)strlen(server_argv)); p += sprintf(p, "\r\n"); if(strlen(server_argv)) p += sprintf(p, "%s", server_argv); request_len = p - request; } else { p = request; if(strlen(server_argv) > 0) p += sprintf(p, "GET /%s?%s HTTP/1.1\r\n", server_url, server_argv); else p += sprintf(p, "GET /%s HTTP/1.1\r\n", server_url); p += sprintf(p, "Host: %s:%d\r\n", server_host, server_port); if(is_keepalive) p += sprintf(p, "Connection: Keep-Alive\r\n"); p += sprintf(p, "\r\n"); request_len = p - request; } if((hent = gethostbyname(server_host)) == NULL) { fprintf(stderr, "resolve hostname:%s failed, %s\n", server_host, strerror(h_errno)); _exit(-1); } else { //memcpy(&ip, &(hent->h_addr), sizeof(int)); sprintf(server_ip, "%s", inet_ntoa(*((struct in_addr *)(hent->h_addr)))); if(is_verbosity) { fprintf(stdout, "ip:%s request:%s\n", server_ip, request); } } //_exit(-1); /* locale */ setlocale(LC_ALL, "C"); /* signal */ signal(SIGTERM, &benchmark_stop); signal(SIGINT, &benchmark_stop); signal(SIGHUP, &benchmark_stop); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); //daemon if(is_daemon) { pid = fork(); switch (pid) { case -1: perror("fork()"); exit(EXIT_FAILURE); break; case 0: //child if(setsid() == -1) exit(EXIT_FAILURE); break; default://parent _exit(EXIT_SUCCESS); break; } } setrlimiter("RLIMIT_NOFILE", RLIMIT_NOFILE, 65536); if((sbase = sbase_init()) == NULL) { exit(EXIT_FAILURE); return -1; } sbase->nchilds = 0; sbase->usec_sleep = 1000; sbase->connections_limit = 65536; TIMER_INIT(timer); MUTEX_INIT(mutex); if(log_level > 1)sbase->set_evlog(sbase, "/tmp/benchmark_ev.log"); if(log_level > 0) sbase->set_evlog_level(sbase, log_level); if((service = service_init())) { service->working_mode = 1; service->nprocthreads = workers; service->niodaemons = niodaemons; service->ndaemons = 0; service->use_cond_wait = 1; service->flag |= SB_USE_OUTDAEMON|SB_USE_COND; if(is_realtime) service->flag |= (SB_SCHED_FIFO|SB_SCHED_RR) & is_realtime; if(socket_option == 1) service->flag |= SB_SO_LINGER; if(tcp_option == 1) service->flag |= SB_TCP_NODELAY; service->service_type = C_SERVICE; service->family = AF_INET; service->sock_type = SOCK_STREAM; service->service_name = "benchmark"; service->session.flags = SB_NONBLOCK; service->session.packet_type = PACKET_DELIMITER; service->session.packet_delimiter = "\r\n\r\n"; service->session.packet_delimiter_length = 4; service->session.packet_handler = &benchmark_packet_handler; service->session.data_handler = &benchmark_data_handler; service->session.transaction_handler = &benchmark_trans_handler; service->session.error_handler = &benchmark_error_handler; service->session.timeout_handler = &benchmark_timeout_handler; service->session.ok_handler = &benchmark_ok_handler; service->session.buffer_size = 65536; service->set_heartbeat(service, 1000000, &benchmark_heartbeat_handler, NULL); //service->set_session(service, &session); service->set_log(service, "/tmp/benchmark.log"); service->set_log_level(service, log_level); LOGGER_INIT(logger, "/tmp/benchmark_res.log"); if(sbase->add_service(sbase, service) == 0) { sbase->running(sbase, 0); //sbase->running(sbase, 3600); //sbase->running(sbase, 90000000);sbase->stop(sbase); } else fprintf(stderr, "add service failed, %s", strerror(errno)); } sbase->clean(sbase); MUTEX_DESTROY(mutex); return 0; }
int main(int argc, char **argv) { int i; sigset_t set; #if ENABLE_LINUXDVB uint32_t adapter_mask; #endif /* Defaults */ log_stderr = 1; log_decorate = isatty(2); log_debug_to_syslog = 0; log_debug_to_console = 0; log_debug_to_path = 0; log_path = NULL; tvheadend_webui_port = 9981; tvheadend_webroot = NULL; tvheadend_htsp_port = 9982; tvheadend_htsp_port_extra = 0; /* Command line options */ int opt_help = 0, opt_version = 0, opt_fork = 0, opt_firstrun = 0, opt_debug = 0, opt_syslog = 0, opt_uidebug = 0, opt_abort = 0, opt_noacl = 0, opt_ipv6 = 0; const char *opt_config = NULL, *opt_user = NULL, *opt_group = NULL, *opt_pidpath = "/var/run/tvheadend.pid", #if ENABLE_LINUXDVB *opt_dvb_adapters = NULL, *opt_dvb_raw = NULL, #endif *opt_rawts = NULL, *opt_subscribe = NULL; cmdline_opt_t cmdline_opts[] = { { 0, NULL, "Generic Options", OPT_BOOL, NULL }, { 'h', "help", "Show this page", OPT_BOOL, &opt_help }, { 'v', "version", "Show version infomation", OPT_BOOL, &opt_version }, { 0, NULL, "Service Configuration", OPT_BOOL, NULL }, { 'c', "config", "Alternate config path", OPT_STR, &opt_config }, { 'f', "fork", "Fork and run as daemon", OPT_BOOL, &opt_fork }, { 'u', "user", "Run as user", OPT_STR, &opt_user }, { 'g', "group", "Run as group", OPT_STR, &opt_group }, { 'p', "pid", "Alternate pid path", OPT_STR, &opt_pidpath }, { 'C', "firstrun", "If no useraccount exist then create one with\n" "no username and no password. Use with care as\n" "it will allow world-wide administrative access\n" "to your Tvheadend installation until you edit\n" "the access-control from within the Tvheadend UI", OPT_BOOL, &opt_firstrun }, #if ENABLE_LINUXDVB { 'a', "adapters", "Use only specified DVB adapters", OPT_STR, &opt_dvb_adapters }, #endif { 0, NULL, "Server Connectivity", OPT_BOOL, NULL }, { '6', "ipv6", "Listen on IPv6", OPT_BOOL, &opt_ipv6 }, { 0, "http_port", "Specify alternative http port", OPT_INT, &tvheadend_webui_port }, { 0, "http_root", "Specify alternative http webroot", OPT_STR, &tvheadend_webroot }, { 0, "htsp_port", "Specify alternative htsp port", OPT_INT, &tvheadend_htsp_port }, { 0, "htsp_port2", "Specify extra htsp port", OPT_INT, &tvheadend_htsp_port_extra }, { 0, NULL, "Debug Options", OPT_BOOL, NULL }, { 'd', "debug", "Enable all debug", OPT_BOOL, &opt_debug }, { 's', "syslog", "Enable debug to syslog", OPT_BOOL, &opt_syslog }, { 0, "uidebug", "Enable webUI debug", OPT_BOOL, &opt_uidebug }, { 'l', "log", "Log to file", OPT_STR, &log_path }, { 'A', "abort", "Immediately abort", OPT_BOOL, &opt_abort }, { 0, "noacl", "Disable all access control checks", OPT_BOOL, &opt_noacl }, #if ENABLE_LINUXDVB { 'R', "dvbraw", "Use rawts file to create virtual adapter", OPT_STR, &opt_dvb_raw }, #endif { 'r', "rawts", "Use rawts file to generate virtual services", OPT_STR, &opt_rawts }, { 'j', "join", "Subscribe to a service permanently", OPT_STR, &opt_subscribe } }; /* Get current directory */ tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0]))); /* Set locale */ setlocale(LC_ALL, ""); /* make sure the timezone is set */ tzset(); /* Process command line */ for (i = 1; i < argc; i++) { /* Find option */ cmdline_opt_t *opt = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]); if (!opt) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), "invalid option specified [%s]", argv[i]); /* Process */ if (opt->type == OPT_BOOL) *((int*)opt->param) = 1; else if (++i == argc) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), "option %s requires a value", opt->lopt); else if (opt->type == OPT_INT) *((int*)opt->param) = atoi(argv[i]); else *((char**)opt->param) = argv[i]; /* Stop processing */ if (opt_help) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL); if (opt_version) show_version(argv[0]); } /* Additional cmdline processing */ log_debug_to_console = opt_debug; log_debug_to_syslog = opt_syslog; log_debug_to_path = opt_debug; tvheadend_webui_debug = opt_debug || opt_uidebug; tvhlog(LOG_INFO, "START", "initialising"); #if ENABLE_LINUXDVB if (!opt_dvb_adapters) { adapter_mask = ~0; } else { char *p, *r, *e; adapter_mask = 0x0; p = strtok_r((char*)opt_dvb_adapters, ",", &r); while (p) { int a = strtol(p, &e, 10); if (*e != 0 || a < 0 || a > 31) { tvhlog(LOG_ERR, "START", "Invalid adapter number '%s'", p); return 1; } adapter_mask |= (1 << a); p = strtok_r(NULL, ",", &r); } if (!adapter_mask) { tvhlog(LOG_ERR, "START", "No adapters specified!"); return 1; } } #endif if (tvheadend_webroot) { char *tmp; if (*tvheadend_webroot == '/') tmp = strdup(tvheadend_webroot); else { tmp = malloc(strlen(tvheadend_webroot)+1); *tmp = '/'; strcpy(tmp+1, tvheadend_webroot); } if (tmp[strlen(tmp)-1] == '/') tmp[strlen(tmp)-1] = '\0'; tvheadend_webroot = tmp; } signal(SIGPIPE, handle_sigpipe); // will be redundant later /* Daemonise */ if(opt_fork) { const char *homedir; gid_t gid; uid_t uid; struct group *grp = getgrnam(opt_group ?: "video"); struct passwd *pw = opt_user ? getpwnam(opt_user) : NULL; FILE *pidfile = fopen(opt_pidpath, "w+"); if(grp != NULL) { gid = grp->gr_gid; } else { gid = 1; } if (pw != NULL) { if (getuid() != pw->pw_uid) { gid_t glist[10]; int gnum; gnum = get_user_groups(pw, glist, 10); if (setgroups(gnum, glist)) { tvhlog(LOG_ALERT, "START", "setgroups() failed, do you have permission?"); return 1; } } uid = pw->pw_uid; homedir = pw->pw_dir; setenv("HOME", homedir, 1); } else { uid = 1; } if ((getgid() != gid) && setgid(gid)) { tvhlog(LOG_ALERT, "START", "setgid() failed, do you have permission?"); return 1; } if ((getuid() != uid) && setuid(uid)) { tvhlog(LOG_ALERT, "START", "setuid() failed, do you have permission?"); return 1; } if(daemon(0, 0)) { exit(2); } if(pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } umask(0); } /* Setup logging */ log_stderr = !opt_fork; log_decorate = isatty(2); openlog("tvheadend", LOG_PID, LOG_DAEMON); /* Initialise configuration */ hts_settings_init(opt_config); /* Setup global mutexes */ pthread_mutex_init(&ffmpeg_lock, NULL); pthread_mutex_init(&fork_lock, NULL); pthread_mutex_init(&global_lock, NULL); pthread_mutex_lock(&global_lock); time(&dispatch_clock); /* Signal handling */ sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); trap_init(argv[0]); /** * Initialize subsystems */ #if ENABLE_LIBAV libav_init(); #endif config_init(); imagecache_init(); service_init(); channels_init(); subscription_init(); access_init(opt_firstrun, opt_noacl); #if ENABLE_LINUXDVB muxes_init(); dvb_init(adapter_mask, opt_dvb_raw); #endif iptv_input_init(); #if ENABLE_V4L v4l_init(); #endif #if ENABLE_TIMESHIFT timeshift_init(); #endif tcp_server_init(opt_ipv6); http_server_init(); webui_init(); serviceprobe_init(); #if ENABLE_CWC cwc_init(); capmt_init(); #if (!ENABLE_DVBCSA) ffdecsa_init(); #endif #endif epggrab_init(); epg_init(); dvr_init(); htsp_init(); if(opt_rawts != NULL) rawts_init(opt_rawts); if(opt_subscribe != NULL) subscription_dummy_join(opt_subscribe, 1); #ifdef CONFIG_AVAHI avahi_init(); #endif epg_updated(); // cleanup now all prev ref's should have been created pthread_mutex_unlock(&global_lock); /** * Wait for SIGTERM / SIGINT, but only in this thread */ running = 1; sigemptyset(&set); sigaddset(&set, SIGTERM); sigaddset(&set, SIGINT); signal(SIGTERM, doexit); signal(SIGINT, doexit); pthread_sigmask(SIG_UNBLOCK, &set, NULL); tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, " "running as PID:%d UID:%d GID:%d, settings located in '%s'", tvheadend_version, getpid(), getuid(), getgid(), hts_settings_get_root()); if(opt_abort) abort(); mainloop(); epg_save(); #if ENABLE_TIMESHIFT timeshift_term(); #endif tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend"); if(opt_fork) unlink(opt_pidpath); return 0; }
/** * The main function for the service. * Called by the services API when starting unbound on windows in background. * Arguments could have been present in the string 'path'. * @param argc: nr args * @param argv: arg text. */ static void service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv)) { struct config_file* cfg = NULL; struct daemon* daemon = NULL; service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)hdlr); if(!service_status_handle) { reportev("Could not RegisterServiceCtrlHandler"); return; } service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwServiceSpecificExitCode = 0; /* see if we have root anchor update enabled */ call_root_update(); /* we are now starting up */ report_status(SERVICE_START_PENDING, NO_ERROR, 3000); if(!service_init(0, &daemon, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } /* event that gets signalled when we want to quit; it * should get registered in the worker-0 waiting loop. */ service_stop_event = WSACreateEvent(); if(service_stop_event == WSA_INVALID_EVENT) { log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError())); reportev("Could not WSACreateEvent"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } if(!WSAResetEvent(service_stop_event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } /* SetServiceStatus SERVICE_RUNNING;*/ report_status(SERVICE_RUNNING, NO_ERROR, 0); verbose(VERB_QUERY, "winservice - init complete"); /* daemon performs work */ while(!service_stop_shutdown) { daemon_fork(daemon); if(!service_stop_shutdown) { daemon_cleanup(daemon); config_delete(cfg); cfg=NULL; if(!service_init(1, &daemon, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } } } /* exit */ verbose(VERB_ALGO, "winservice - cleanup."); report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); service_deinit(daemon, cfg); free(service_cfgfile); if(service_stop_event) (void)WSACloseEvent(service_stop_event); verbose(VERB_QUERY, "winservice - full stop"); report_status(SERVICE_STOPPED, NO_ERROR, 0); }
int main(int argc, char **argv) { int c; int forkaway = 0; FILE *pidfile; const char *pidpath = "/var/run/tvheadend.pid"; struct group *grp; struct passwd *pw; char *webroot; const char *usernam = NULL; const char *groupnam = NULL; int logfacility = LOG_DAEMON; int createdefault = 0; sigset_t set; const char *homedir; const char *rawts_input = NULL; #if ENABLE_LINUXDVB const char *dvb_rawts_input = NULL; #endif const char *join_transport = NULL; const char *confpath = NULL; char *p, *endp; uint32_t adapter_mask = 0xffffffff; int crash = 0; webui_port = 9981; htsp_port = 9982; gid_t gid; uid_t uid; /* Get current directory */ tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0]))); /* Set locale */ setlocale(LC_ALL, ""); // make sure the timezone is set tzset(); while((c = getopt(argc, argv, "Aa:fp:u:g:c:Chdr:j:sw:e:E:R:W:")) != -1) { switch(c) { case 'a': adapter_mask = 0x0; p = strtok(optarg, ","); if (p != NULL) { do { int adapter = strtol(p, &endp, 10); if (*endp != 0 || adapter < 0 || adapter > 31) { fprintf(stderr, "Invalid adapter number '%s'\n", p); return 1; } adapter_mask |= (1 << adapter); } while ((p = strtok(NULL, ",")) != NULL); if (adapter_mask == 0x0) { fprintf(stderr, "No adapters specified!\n"); return 1; } } else { usage(argv[0]); } break; case 'A': crash = 1; break; case 'f': forkaway = 1; break; case 'p': pidpath = optarg; break; case 'w': webui_port = atoi(optarg); break; case 'e': htsp_port = atoi(optarg); break; case 'E': htsp_port_extra = atoi(optarg); break; case 'u': usernam = optarg; break; case 'g': groupnam = optarg; break; case 'c': confpath = optarg; break; case 'd': log_debug_to_console = 1; break; case 's': log_debug_to_syslog = 1; break; case 'C': createdefault = 1; break; case 'r': rawts_input = optarg; break; #if ENABLE_LINUXDVB case 'R': dvb_rawts_input = optarg; break; #endif case 'j': join_transport = optarg; break; case 'W': webroot = malloc(strlen(optarg) + (*optarg == '/' ? 0 : 1)); if (*optarg != '/') { *webroot = '/'; strcpy(webroot+1, optarg); } else { strcpy(webroot, optarg); } if (webroot[strlen(webroot)-1] == '/') webroot[strlen(webroot)-1] = '\0'; tvheadend_webroot = webroot; break; default: usage(argv[0]); } } signal(SIGPIPE, handle_sigpipe); log_stderr = 1; log_decorate = isatty(2); if(forkaway) { grp = getgrnam(groupnam ?: "video"); pw = usernam ? getpwnam(usernam) : NULL; pidfile = fopen(pidpath, "w+"); if(grp != NULL) { gid = grp->gr_gid; } else { gid = 1; } if (pw != NULL) { if (getuid() != pw->pw_uid) { gid_t glist[10]; int gnum; gnum = get_user_groups(pw, glist, 10); if (setgroups(gnum, glist)) { tvhlog(LOG_ALERT, "START", "setgroups() failed, do you have permission?"); return 1; } } uid = pw->pw_uid; homedir = pw->pw_dir; setenv("HOME", homedir, 1); } else { uid = 1; } if ((getgid() != gid) && setgid(gid)) { tvhlog(LOG_ALERT, "START", "setgid() failed, do you have permission?"); return 1; } if ((getuid() != uid) && setuid(uid)) { tvhlog(LOG_ALERT, "START", "setuid() failed, do you have permission?"); return 1; } if(daemon(0, 0)) { exit(2); } if(pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } umask(0); } log_stderr = !forkaway; log_decorate = isatty(2); sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); openlog("tvheadend", LOG_PID, logfacility); hts_settings_init(confpath); pthread_mutex_init(&ffmpeg_lock, NULL); pthread_mutex_init(&fork_lock, NULL); pthread_mutex_init(&global_lock, NULL); pthread_mutex_lock(&global_lock); time(&dispatch_clock); trap_init(argv[0]); /** * Initialize subsystems */ config_init(); imagecache_init(); service_init(); channels_init(); subscription_init(); access_init(createdefault); #if ENABLE_LINUXDVB muxes_init(); dvb_init(adapter_mask, dvb_rawts_input); #endif iptv_input_init(); #if ENABLE_V4L v4l_init(); #endif tcp_server_init(); http_server_init(); webui_init(); serviceprobe_init(); #if ENABLE_CWC cwc_init(); capmt_init(); #if (!ENABLE_DVBCSA) ffdecsa_init(); #endif #endif epggrab_init(); epg_init(); dvr_init(); htsp_init(); if(rawts_input != NULL) rawts_init(rawts_input); if(join_transport != NULL) subscription_dummy_join(join_transport, 1); #ifdef CONFIG_AVAHI avahi_init(); #endif epg_updated(); // cleanup now all prev ref's should have been created pthread_mutex_unlock(&global_lock); /** * Wait for SIGTERM / SIGINT, but only in this thread */ running = 1; sigemptyset(&set); sigaddset(&set, SIGTERM); sigaddset(&set, SIGINT); signal(SIGTERM, doexit); signal(SIGINT, doexit); pthread_sigmask(SIG_UNBLOCK, &set, NULL); tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, " "running as PID:%d UID:%d GID:%d, settings located in '%s'", tvheadend_version, getpid(), getuid(), getgid(), hts_settings_get_root()); if(crash) abort(); mainloop(); epg_save(); tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend"); if(forkaway) unlink("/var/run/tvheadend.pid"); return 0; }
bool master_threads::run_alone(const char* addrs, const char* path /* = NULL */, unsigned int count /* = 1 */, int threads_count /* = 1 */) { // 每个进程只能有一个实例在运行 acl_assert(has_called == false); has_called = true; daemon_mode_ = false; acl_assert(addrs && *addrs); __count_limit = count; #ifdef WIN32 acl_init(); #endif std::vector<ACL_VSTREAM*> sstreams; ACL_EVENT* eventp = acl_event_new_select_thr(1, 0); set_event(eventp); // 设置基类的事件句柄 ACL_ARGV* tokens = acl_argv_split(addrs, ";,| \t"); ACL_ITER iter; acl_foreach(iter, tokens) { const char* addr = (const char*) iter.data; ACL_VSTREAM* sstream = acl_vstream_listen(addr, 128); if (sstream == NULL) { logger_error("listen %s error(%s)", addr, acl_last_serror()); acl_argv_free(tokens); close_sstreams(eventp, sstreams); acl_event_free(eventp); return false; } acl_event_enable_listen(eventp, sstream, 0, listen_callback, sstream); sstreams.push_back(sstream); } acl_argv_free(tokens); // 初始化配置参数 conf_.load(path); service_pre_jail(NULL); service_init(NULL); if (threads_count > 1) { __thread_pool = acl_thread_pool_create(threads_count, 120); acl_pthread_pool_atinit(__thread_pool, thread_begin, NULL); acl_pthread_pool_atfree(__thread_pool, thread_finish, NULL); } else thread_init(NULL); while (!__stop) acl_event_loop(eventp); if (__thread_pool) acl_pthread_pool_destroy(__thread_pool); else thread_exit(NULL); service_exit(NULL); // 必须在调用 acl_event_free 前调用 close_sstreams,因为在关闭 // 网络流对象时依然有对 ACL_EVENT 引擎的使用 close_sstreams(eventp, sstreams); acl_event_free(eventp); eventp = NULL; return true; }
int main(int argc, char **argv) { int c; int forkaway = 0; FILE *pidfile; const char *pidpath = "/var/run/tvheadend.pid"; struct group *grp; struct passwd *pw; const char *usernam = NULL; const char *groupnam = NULL; int logfacility = LOG_DAEMON; int createdefault = 0; sigset_t set; const char *homedir; const char *rawts_input = NULL; const char *join_transport = NULL; const char *confpath = NULL; char *p, *endp; uint32_t adapter_mask = 0xffffffff; int crash = 0; // make sure the timezone is set tzset(); while((c = getopt(argc, argv, "Aa:fp:u:g:c:Chdr:j:s")) != -1) { switch(c) { case 'a': adapter_mask = 0x0; p = strtok(optarg, ","); if (p != NULL) { do { int adapter = strtol(p, &endp, 10); if (*endp != 0 || adapter < 0 || adapter > 31) { fprintf(stderr, "Invalid adapter number '%s'\n", p); return 1; } adapter_mask |= (1 << adapter); } while ((p = strtok(NULL, ",")) != NULL); if (adapter_mask == 0x0) { fprintf(stderr, "No adapters specified!\n"); return 1; } } else { usage(argv[0]); } break; case 'A': crash = 1; break; case 'f': forkaway = 1; break; case 'p': pidpath = optarg; break; case 'u': usernam = optarg; break; case 'g': groupnam = optarg; break; case 'c': confpath = optarg; break; case 'd': log_debug_to_console = 1; break; case 's': log_debug_to_syslog = 1; break; case 'C': createdefault = 1; break; case 'r': rawts_input = optarg; break; case 'j': join_transport = optarg; break; default: usage(argv[0]); break; } } signal(SIGPIPE, handle_sigpipe); grp = getgrnam(groupnam ?: "video"); pw = usernam ? getpwnam(usernam) : NULL; if(forkaway) { if(daemon(0, 0)) { exit(2); } pidfile = fopen(pidpath, "w+"); if(pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } if(grp != NULL) { setgid(grp->gr_gid); } else { setgid(1); } if(pw != NULL) { setuid(pw->pw_uid); } else { setuid(1); } if(pw != NULL) { homedir = pw->pw_dir; setenv("HOME", homedir, 1); } umask(0); } log_stderr = !forkaway; log_decorate = isatty(2); sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); openlog("tvheadend", LOG_PID, logfacility); hts_settings_init(confpath); pthread_mutex_init(&ffmpeg_lock, NULL); pthread_mutex_init(&fork_lock, NULL); pthread_mutex_init(&global_lock, NULL); pthread_mutex_lock(&global_lock); time(&dispatch_clock); trap_init(argv[0]); /** * Initialize subsystems */ xmltv_init(); /* Must be initialized before channels */ service_init(); channels_init(); access_init(createdefault); tcp_server_init(); #if ENABLE_LINUXDVB dvb_init(adapter_mask); #endif iptv_input_init(); #if ENABLE_V4L v4l_init(); #endif http_server_init(); webui_init(tvheadend_dataroot()); serviceprobe_init(); cwc_init(); capmt_init(); epg_init(); dvr_init(); htsp_init(); ffdecsa_init(); if(rawts_input != NULL) rawts_init(rawts_input); if(join_transport != NULL) subscription_dummy_join(join_transport, 1); #ifdef CONFIG_AVAHI avahi_init(); #endif pthread_mutex_unlock(&global_lock); /** * Wait for SIGTERM / SIGINT, but only in this thread */ running = 1; sigemptyset(&set); sigaddset(&set, SIGTERM); sigaddset(&set, SIGINT); signal(SIGTERM, doexit); signal(SIGINT, doexit); pthread_sigmask(SIG_UNBLOCK, &set, NULL); tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, " "running as PID:%d UID:%d GID:%d, settings located in '%s', " "dataroot: %s", tvheadend_version, getpid(), getuid(), getgid(), hts_settings_get_root(), tvheadend_dataroot() ?: "<Embedded file system>"); if(crash) abort(); mainloop(); epg_save(); tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend"); if(forkaway) unlink("/var/run/tvheadend.pid"); return 0; }
// NOTE: this function needs to call RegisterServiceCtrlHandlerEx and // SetServiceStatus in all circumstances if brickd is running as service static int generic_main(int log_to_file, int debug) { int exit_code = EXIT_FAILURE; const char *mutex_name = "Global\\Tinkerforge-Brick-Daemon-Single-Instance"; HANDLE mutex_handle = NULL; int mutex_error = 0; DWORD service_exit_code = NO_ERROR; int rc; char filename[1024]; int i; FILE *logfile = NULL; WSADATA wsa_data; DEV_BROADCAST_DEVICEINTERFACE notification_filter; HDEVNOTIFY notification_handle; mutex_handle = OpenMutex(SYNCHRONIZE, FALSE, mutex_name); if (mutex_handle == NULL) { rc = GetLastError(); if (rc == ERROR_ACCESS_DENIED) { rc = service_is_running(); if (rc < 0) { mutex_error = 1; // FIXME: set service_exit_code goto error_mutex; } else if (rc) { mutex_error = 1; service_exit_code = ERROR_SERVICE_ALREADY_RUNNING; log_error("Could not start as %s, another instance is already running as service", _run_as_service ? "service" : "console application"); goto error_mutex; } } if (rc != ERROR_FILE_NOT_FOUND) { mutex_error = 1; // FIXME: set service_exit_code rc += ERRNO_WINAPI_OFFSET; log_error("Could not open single instance mutex: %s (%d)", get_errno_name(rc), rc); goto error_mutex; } } if (mutex_handle != NULL) { mutex_error = 1; service_exit_code = ERROR_SERVICE_ALREADY_RUNNING; log_error("Could not start as %s, another instance is already running", _run_as_service ? "service" : "console application"); goto error_mutex; } mutex_handle = CreateMutex(NULL, FALSE, mutex_name); if (mutex_handle == NULL) { mutex_error = 1; // FIXME: set service_exit_code rc = ERRNO_WINAPI_OFFSET + GetLastError(); log_error("Could not create single instance mutex: %s (%d)", get_errno_name(rc), rc); goto error_mutex; } if (!_run_as_service && !SetConsoleCtrlHandler(console_ctrl_handler, TRUE)) { rc = ERRNO_WINAPI_OFFSET + GetLastError(); log_warn("Could not set console control handler: %s (%d)", get_errno_name(rc), rc); } if (log_to_file) { if (GetModuleFileName(NULL, filename, sizeof(filename)) == 0) { rc = ERRNO_WINAPI_OFFSET + GetLastError(); log_warn("Could not get module file name: %s (%d)", get_errno_name(rc), rc); } else { i = strlen(filename); if (i < 4) { log_warn("Module file name '%s' is too short", filename); } else { strcpy(filename + i - 3, "log"); logfile = fopen(filename, "a+"); if (logfile == NULL) { log_warn("Could not open logfile '%s'", filename); } else { log_set_file(logfile); } } } } if (debug) { log_set_level(LOG_CATEGORY_EVENT, LOG_LEVEL_DEBUG); log_set_level(LOG_CATEGORY_USB, LOG_LEVEL_DEBUG); log_set_level(LOG_CATEGORY_NETWORK, LOG_LEVEL_DEBUG); log_set_level(LOG_CATEGORY_HOTPLUG, LOG_LEVEL_DEBUG); log_set_level(LOG_CATEGORY_OTHER, LOG_LEVEL_DEBUG); } else { log_set_level(LOG_CATEGORY_EVENT, config_get_log_level(LOG_CATEGORY_EVENT)); log_set_level(LOG_CATEGORY_USB, config_get_log_level(LOG_CATEGORY_USB)); log_set_level(LOG_CATEGORY_NETWORK, config_get_log_level(LOG_CATEGORY_NETWORK)); log_set_level(LOG_CATEGORY_HOTPLUG, config_get_log_level(LOG_CATEGORY_HOTPLUG)); log_set_level(LOG_CATEGORY_OTHER, config_get_log_level(LOG_CATEGORY_OTHER)); } if (_run_as_service) { log_info("Brick Daemon %s started (as service)", VERSION_STRING); } else { log_info("Brick Daemon %s started", VERSION_STRING); } if (config_has_error()) { log_warn("Errors found in config file '%s', run with --check-config option for details", _config_filename); } // initialize service status error_mutex: if (_run_as_service) { if (service_init(service_control_handler) < 0) { // FIXME: set service_exit_code goto error; } if (!mutex_error) { // service is starting service_set_status(SERVICE_START_PENDING, NO_ERROR); } } if (mutex_error) { goto error; } // initialize WinSock2 if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) { // FIXME: set service_exit_code rc = ERRNO_WINAPI_OFFSET + WSAGetLastError(); log_error("Could not initialize Windows Sockets 2.2: %s (%d)", get_errno_name(rc), rc); goto error_event; } if (event_init() < 0) { // FIXME: set service_exit_code goto error_event; } if (usb_init() < 0) { // FIXME: set service_exit_code goto error_usb; } // create notification pipe if (pipe_create(_notification_pipe) < 0) { // FIXME: set service_exit_code log_error("Could not create notification pipe: %s (%d)", get_errno_name(errno), errno); goto error_pipe; } if (event_add_source(_notification_pipe[0], EVENT_SOURCE_TYPE_GENERIC, EVENT_READ, forward_notifications, NULL) < 0) { // FIXME: set service_exit_code goto error_pipe_add; } // register device notification ZeroMemory(¬ification_filter, sizeof(notification_filter)); notification_filter.dbcc_size = sizeof(notification_filter); notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; notification_filter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; if (_run_as_service) { notification_handle = RegisterDeviceNotification((HANDLE)service_get_status_handle(), ¬ification_filter, DEVICE_NOTIFY_SERVICE_HANDLE); } else { if (message_pump_start() < 0) { // FIXME: set service_exit_code goto error_pipe_add; } notification_handle = RegisterDeviceNotification(_message_pump_hwnd, ¬ification_filter, DEVICE_NOTIFY_WINDOW_HANDLE); } if (notification_handle == NULL) { // FIXME: set service_exit_code rc = ERRNO_WINAPI_OFFSET + GetLastError(); log_error("Could not register for device notification: %s (%d)", get_errno_name(rc), rc); goto error_notification; } if (network_init() < 0) { // FIXME: set service_exit_code goto error_network; } // running if (_run_as_service) { service_set_status(SERVICE_RUNNING, NO_ERROR); } if (event_run() < 0) { // FIXME: set service_exit_code goto error_run; } exit_code = EXIT_SUCCESS; error_run: network_exit(); error_network: UnregisterDeviceNotification(notification_handle); error_notification: if (!_run_as_service) { message_pump_stop(); } event_remove_source(_notification_pipe[0], EVENT_SOURCE_TYPE_GENERIC); error_pipe_add: pipe_destroy(_notification_pipe); error_pipe: usb_exit(); error_usb: event_exit(); error_event: log_info("Brick Daemon %s stopped", VERSION_STRING); error: log_exit(); config_exit(); if (_run_as_service) { // because the service process can be terminated at any time after // entering SERVICE_STOPPED state the mutex is closed beforehand, // even though this creates a tiny time window in which the service // is still running but the mutex is not held anymore if (mutex_handle != NULL) { CloseHandle(mutex_handle); } // service is now stopped service_set_status(SERVICE_STOPPED, service_exit_code); } else { if (_pause_before_exit) { printf("Press any key to exit...\n"); getch(); } if (mutex_handle != NULL) { CloseHandle(mutex_handle); } } return exit_code; }
int main(int argc, char **argv) { int i; sigset_t set; #if ENABLE_LINUXDVB uint32_t adapter_mask; #endif int log_level = LOG_INFO; int log_options = TVHLOG_OPT_MILLIS | TVHLOG_OPT_STDERR | TVHLOG_OPT_SYSLOG; const char *log_debug = NULL, *log_trace = NULL; char buf[512]; main_tid = pthread_self(); /* Setup global mutexes */ pthread_mutex_init(&ffmpeg_lock, NULL); pthread_mutex_init(&fork_lock, NULL); pthread_mutex_init(&global_lock, NULL); pthread_mutex_init(&atomic_lock, NULL); pthread_cond_init(>imer_cond, NULL); /* Defaults */ tvheadend_webui_port = 9981; tvheadend_webroot = NULL; tvheadend_htsp_port = 9982; tvheadend_htsp_port_extra = 0; /* Command line options */ int opt_help = 0, opt_version = 0, opt_fork = 0, opt_firstrun = 0, opt_stderr = 0, opt_syslog = 0, opt_uidebug = 0, opt_abort = 0, opt_noacl = 0, opt_fileline = 0, opt_threadid = 0, opt_ipv6 = 0, opt_tsfile_tuner = 0, opt_dump = 0; const char *opt_config = NULL, *opt_user = NULL, *opt_group = NULL, *opt_logpath = NULL, *opt_log_debug = NULL, *opt_log_trace = NULL, *opt_pidpath = "/var/run/tvheadend.pid", #if ENABLE_LINUXDVB *opt_dvb_adapters = NULL, #endif *opt_bindaddr = NULL, *opt_subscribe = NULL; str_list_t opt_tsfile = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) }; cmdline_opt_t cmdline_opts[] = { { 0, NULL, "Generic Options", OPT_BOOL, NULL }, { 'h', "help", "Show this page", OPT_BOOL, &opt_help }, { 'v', "version", "Show version infomation", OPT_BOOL, &opt_version }, { 0, NULL, "Service Configuration", OPT_BOOL, NULL }, { 'c', "config", "Alternate config path", OPT_STR, &opt_config }, { 'f', "fork", "Fork and run as daemon", OPT_BOOL, &opt_fork }, { 'u', "user", "Run as user", OPT_STR, &opt_user }, { 'g', "group", "Run as group", OPT_STR, &opt_group }, { 'p', "pid", "Alternate pid path", OPT_STR, &opt_pidpath }, { 'C', "firstrun", "If no user account exists then create one with\n" "no username and no password. Use with care as\n" "it will allow world-wide administrative access\n" "to your Tvheadend installation until you edit\n" "the access-control from within the Tvheadend UI", OPT_BOOL, &opt_firstrun }, #if ENABLE_LINUXDVB { 'a', "adapters", "Only use specified DVB adapters (comma separated)", OPT_STR, &opt_dvb_adapters }, #endif { 0, NULL, "Server Connectivity", OPT_BOOL, NULL }, { '6', "ipv6", "Listen on IPv6", OPT_BOOL, &opt_ipv6 }, { 'b', "bindaddr", "Specify bind address", OPT_STR, &opt_bindaddr}, { 0, "http_port", "Specify alternative http port", OPT_INT, &tvheadend_webui_port }, { 0, "http_root", "Specify alternative http webroot", OPT_STR, &tvheadend_webroot }, { 0, "htsp_port", "Specify alternative htsp port", OPT_INT, &tvheadend_htsp_port }, { 0, "htsp_port2", "Specify extra htsp port", OPT_INT, &tvheadend_htsp_port_extra }, { 0, NULL, "Debug Options", OPT_BOOL, NULL }, { 'd', "stderr", "Enable debug on stderr", OPT_BOOL, &opt_stderr }, { 's', "syslog", "Enable debug to syslog", OPT_BOOL, &opt_syslog }, { 'l', "logfile", "Enable debug to file", OPT_STR, &opt_logpath }, { 0, "debug", "Enable debug subsystems", OPT_STR, &opt_log_debug }, #if ENABLE_TRACE { 0, "trace", "Enable trace subsystems", OPT_STR, &opt_log_trace }, #endif { 0, "fileline", "Add file and line numbers to debug", OPT_BOOL, &opt_fileline }, { 0, "threadid", "Add the thread ID to debug", OPT_BOOL, &opt_threadid }, { 0, "uidebug", "Enable webUI debug (non-minified JS)", OPT_BOOL, &opt_uidebug }, { 'A', "abort", "Immediately abort", OPT_BOOL, &opt_abort }, { 'D', "dump", "Enable coredumps for daemon", OPT_BOOL, &opt_dump }, { 0, "noacl", "Disable all access control checks", OPT_BOOL, &opt_noacl }, { 'j', "join", "Subscribe to a service permanently", OPT_STR, &opt_subscribe }, { 0, NULL, "TODO: testing", OPT_BOOL, NULL }, { 0, "tsfile_tuners", "Number of tsfile tuners", OPT_INT, &opt_tsfile_tuner }, { 0, "tsfile", "tsfile input (mux file)", OPT_STR_LIST, &opt_tsfile }, }; /* Get current directory */ tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0]))); /* Set locale */ setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); /* make sure the timezone is set */ tzset(); /* Process command line */ for (i = 1; i < argc; i++) { /* Find option */ cmdline_opt_t *opt = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]); if (!opt) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), "invalid option specified [%s]", argv[i]); /* Process */ if (opt->type == OPT_BOOL) *((int*)opt->param) = 1; else if (++i == argc) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), "option %s requires a value", opt->lopt); else if (opt->type == OPT_INT) *((int*)opt->param) = atoi(argv[i]); else if (opt->type == OPT_STR_LIST) { str_list_t *strl = opt->param; if (strl->num < strl->max) strl->str[strl->num++] = argv[i]; } else *((char**)opt->param) = argv[i]; /* Stop processing */ if (opt_help) show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL); if (opt_version) show_version(argv[0]); } /* Additional cmdline processing */ #if ENABLE_LINUXDVB if (!opt_dvb_adapters) { adapter_mask = ~0; } else { char *p, *e; char *r = NULL; char *dvb_adapters = strdup(opt_dvb_adapters); adapter_mask = 0x0; p = strtok_r(dvb_adapters, ",", &r); while (p) { int a = strtol(p, &e, 10); if (*e != 0 || a < 0 || a > 31) { tvhlog(LOG_ERR, "START", "Invalid adapter number '%s'", p); free(dvb_adapters); return 1; } adapter_mask |= (1 << a); p = strtok_r(NULL, ",", &r); } free(dvb_adapters); if (!adapter_mask) { tvhlog(LOG_ERR, "START", "No adapters specified!"); return 1; } } #endif if (tvheadend_webroot) { char *tmp; if (*tvheadend_webroot == '/') tmp = strdup(tvheadend_webroot); else { tmp = malloc(strlen(tvheadend_webroot)+2); *tmp = '/'; strcpy(tmp+1, tvheadend_webroot); } if (tmp[strlen(tmp)-1] == '/') tmp[strlen(tmp)-1] = '\0'; tvheadend_webroot = tmp; } tvheadend_webui_debug = opt_uidebug; /* Setup logging */ if (isatty(2)) log_options |= TVHLOG_OPT_DECORATE; if (opt_stderr || opt_syslog || opt_logpath) { if (!opt_log_trace && !opt_log_debug) log_debug = "all"; log_level = LOG_DEBUG; if (opt_stderr) log_options |= TVHLOG_OPT_DBG_STDERR; if (opt_syslog) log_options |= TVHLOG_OPT_DBG_SYSLOG; if (opt_logpath) log_options |= TVHLOG_OPT_DBG_FILE; } if (opt_fileline) log_options |= TVHLOG_OPT_FILELINE; if (opt_threadid) log_options |= TVHLOG_OPT_THREAD; if (opt_log_trace) { log_level = LOG_TRACE; log_trace = opt_log_trace; } if (opt_log_debug) log_debug = opt_log_debug; tvhlog_init(log_level, log_options, opt_logpath); tvhlog_set_debug(log_debug); tvhlog_set_trace(log_trace); signal(SIGPIPE, handle_sigpipe); // will be redundant later /* Daemonise */ if(opt_fork) { const char *homedir; gid_t gid; uid_t uid; struct group *grp = getgrnam(opt_group ?: "video"); struct passwd *pw = opt_user ? getpwnam(opt_user) : NULL; FILE *pidfile = fopen(opt_pidpath, "w+"); if(grp != NULL) { gid = grp->gr_gid; } else { gid = 1; } if (pw != NULL) { if (getuid() != pw->pw_uid) { gid_t glist[10]; int gnum; gnum = get_user_groups(pw, glist, 10); if (setgroups(gnum, glist)) { tvhlog(LOG_ALERT, "START", "setgroups() failed, do you have permission?"); return 1; } } uid = pw->pw_uid; homedir = pw->pw_dir; setenv("HOME", homedir, 1); } else { uid = 1; } if ((getgid() != gid) && setgid(gid)) { tvhlog(LOG_ALERT, "START", "setgid() failed, do you have permission?"); return 1; } if ((getuid() != uid) && setuid(uid)) { tvhlog(LOG_ALERT, "START", "setuid() failed, do you have permission?"); return 1; } if(daemon(0, 0)) { exit(2); } if(pidfile != NULL) { fprintf(pidfile, "%d\n", getpid()); fclose(pidfile); } /* Make dumpable */ if (opt_dump) { #ifdef PLATFORM_LINUX if (chdir("/tmp")) tvhwarn("START", "failed to change cwd to /tmp"); prctl(PR_SET_DUMPABLE, 1); #else tvhwarn("START", "Coredumps not implemented on your platform"); #endif } umask(0); } tvheadend_running = 1; /* Start log thread (must be done post fork) */ tvhlog_start(); /* Alter logging */ if (opt_fork) tvhlog_options &= ~TVHLOG_OPT_STDERR; if (!isatty(2)) tvhlog_options &= ~TVHLOG_OPT_DECORATE; /* Initialise clock */ pthread_mutex_lock(&global_lock); time(&dispatch_clock); /* Signal handling */ sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); trap_init(argv[0]); /* Initialise configuration */ uuid_init(); idnode_init(); config_init(opt_config); /** * Initialize subsystems */ api_init(); fsmonitor_init(); #if ENABLE_LIBAV libav_init(); transcoding_init(); #endif imagecache_init(); service_init(); #if ENABLE_TSFILE if(opt_tsfile.num) { tsfile_init(opt_tsfile_tuner ?: opt_tsfile.num); for (i = 0; i < opt_tsfile.num; i++) tsfile_add_file(opt_tsfile.str[i]); } #endif #if ENABLE_MPEGTS_DVB dvb_network_init(); #endif #if ENABLE_IPTV iptv_init(); #endif #if ENABLE_LINUXDVB linuxdvb_init(adapter_mask); #endif channel_init(); subscription_init(); access_init(opt_firstrun, opt_noacl); #if ENABLE_TIMESHIFT timeshift_init(); #endif http_client_init(); tcp_server_init(opt_ipv6); http_server_init(opt_bindaddr); webui_init(); service_mapper_init(); descrambler_init(); epggrab_init(); epg_init(); dvr_init(); htsp_init(opt_bindaddr); if(opt_subscribe != NULL) subscription_dummy_join(opt_subscribe, 1); avahi_init(); epg_updated(); // cleanup now all prev ref's should have been created pthread_mutex_unlock(&global_lock); /** * Wait for SIGTERM / SIGINT, but only in this thread */ sigemptyset(&set); sigaddset(&set, SIGTERM); sigaddset(&set, SIGINT); signal(SIGTERM, doexit); signal(SIGINT, doexit); pthread_sigmask(SIG_UNBLOCK, &set, NULL); tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, " "running as PID:%d UID:%d GID:%d, CWD:%s CNF:%s", tvheadend_version, getpid(), getuid(), getgid(), getcwd(buf, sizeof(buf)), hts_settings_get_root()); if(opt_abort) abort(); mainloop(); tvhftrace("main", htsp_done); tvhftrace("main", http_server_done); tvhftrace("main", webui_done); tvhftrace("main", http_client_done); tvhftrace("main", fsmonitor_done); #if ENABLE_MPEGTS_DVB tvhftrace("main", dvb_network_done); #endif #if ENABLE_IPTV tvhftrace("main", iptv_done); #endif #if ENABLE_LINUXDVB tvhftrace("main", linuxdvb_done); #endif #if ENABLE_TSFILE tvhftrace("main", tsfile_done); #endif // Note: the locking is obviously a bit redundant, but without // we need to disable the gtimer_arm call in epg_save() pthread_mutex_lock(&global_lock); tvhftrace("main", epg_save); #if ENABLE_TIMESHIFT tvhftrace("main", timeshift_term); #endif pthread_mutex_unlock(&global_lock); tvhftrace("main", epggrab_done); tvhftrace("main", tcp_server_done); tvhftrace("main", descrambler_done); tvhftrace("main", service_mapper_done); tvhftrace("main", service_done); tvhftrace("main", channel_done); tvhftrace("main", dvr_done); tvhftrace("main", subscription_done); tvhftrace("main", access_done); tvhftrace("main", epg_done); tvhftrace("main", avahi_done); tvhftrace("main", imagecache_done); tvhftrace("main", idnode_done); tvhftrace("main", lang_code_done); tvhftrace("main", api_done); tvhftrace("main", config_done); tvhftrace("main", hts_settings_done); tvhftrace("main", dvb_done); tvhftrace("main", lang_str_done); tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend"); tvhlog_end(); if(opt_fork) unlink(opt_pidpath); free(opt_tsfile.str); return 0; }
/* Initialize from ini file */ int sbase_initialize(SBASE *sbase, char *conf) { char *logfile = NULL, *s = NULL, *p = NULL; int n = 0; SERVICE *service = NULL; if((dict = iniparser_new(conf)) == NULL) { fprintf(stderr, "Initializing conf:%s failed, %s\n", conf, strerror(errno)); _exit(-1); } /* SBASE */ sbase->nchilds = iniparser_getint(dict, "SBASE:nchilds", 0); sbase->connections_limit = iniparser_getint(dict, "SBASE:connections_limit", SB_CONN_MAX); sbase->usec_sleep = iniparser_getint(dict, "SBASE:usec_sleep", SB_USEC_SLEEP); sbase->set_log(sbase, iniparser_getstr(dict, "SBASE:logfile")); sbase->set_evlog(sbase, iniparser_getstr(dict, "SBASE:evlogfile")); /* LECHOD */ if((service = service_init()) == NULL) { fprintf(stderr, "Initialize service failed, %s", strerror(errno)); _exit(-1); } service->family = iniparser_getint(dict, "LECHOD:inet_family", AF_INET); service->sock_type = iniparser_getint(dict, "LECHOD:socket_type", SOCK_STREAM); service->ip = iniparser_getstr(dict, "LECHOD:service_ip"); service->port = iniparser_getint(dict, "LECHOD:service_port", 80); service->working_mode = iniparser_getint(dict, "LECHOD:working_mode", WORKING_PROC); service->service_type = iniparser_getint(dict, "LECHOD:service_type", C_SERVICE); service->service_name = iniparser_getstr(dict, "LECHOD:service_name"); service->nprocthreads = iniparser_getint(dict, "LECHOD:nprocthreads", 1); service->ndaemons = iniparser_getint(dict, "LECHOD:ndaemons", 0); service->set_log(service, iniparser_getstr(dict, "LECHOD:logfile")); service->session.packet_type = iniparser_getint(dict, "LECHOD:packet_type",PACKET_DELIMITER); service->session.packet_delimiter = iniparser_getstr(dict, "LECHOD:packet_delimiter"); p = s = service->session.packet_delimiter; while(*p != 0 ) { if(*p == '\\' && *(p+1) == 'n') { *s++ = '\n'; p += 2; } else if (*p == '\\' && *(p+1) == 'r') { *s++ = '\r'; p += 2; } else *s++ = *p++; } *s++ = 0; service->session.packet_delimiter_length = strlen(service->session.packet_delimiter); service->session.buffer_size = iniparser_getint(dict, "LECHOD:buffer_size", SB_BUF_SIZE); service->session.packet_reader = &lechod_packet_reader; service->session.packet_handler = &lechod_packet_handler; service->session.data_handler = &lechod_data_handler; service->session.oob_handler = &lechod_oob_handler; /* server */ fprintf(stdout, "Parsing for server...\n"); return sbase->add_service(sbase, service); }
// NOTE: this function needs to call RegisterServiceCtrlHandlerEx and // SetServiceStatus in all circumstances if brickd is running as service static int generic_main(bool log_to_file, bool debug, bool libusb_debug) { int exit_code = EXIT_FAILURE; const char *mutex_name = "Global\\Tinkerforge-Brick-Daemon-Single-Instance"; HANDLE mutex_handle = NULL; bool fatal_error = false; DWORD service_exit_code = NO_ERROR; int rc; char filename[1024]; int i; FILE *log_file = NULL; WSADATA wsa_data; DEV_BROADCAST_DEVICEINTERFACE notification_filter; HDEVNOTIFY notification_handle; mutex_handle = OpenMutex(SYNCHRONIZE, FALSE, mutex_name); if (mutex_handle == NULL) { rc = GetLastError(); if (rc == ERROR_ACCESS_DENIED) { rc = service_is_running(); if (rc < 0) { fatal_error = true; // FIXME: set service_exit_code goto error_mutex; } else if (rc) { fatal_error = true; service_exit_code = ERROR_SERVICE_ALREADY_RUNNING; log_error("Could not start as %s, another instance is already running as service", _run_as_service ? "service" : "console application"); goto error_mutex; } } if (rc != ERROR_FILE_NOT_FOUND) { fatal_error = true; // FIXME: set service_exit_code rc += ERRNO_WINAPI_OFFSET; log_error("Could not open single instance mutex: %s (%d)", get_errno_name(rc), rc); goto error_mutex; } } if (mutex_handle != NULL) { fatal_error = true; service_exit_code = ERROR_SERVICE_ALREADY_RUNNING; log_error("Could not start as %s, another instance is already running", _run_as_service ? "service" : "console application"); goto error_mutex; } mutex_handle = CreateMutex(NULL, FALSE, mutex_name); if (mutex_handle == NULL) { fatal_error = true; // FIXME: set service_exit_code rc = ERRNO_WINAPI_OFFSET + GetLastError(); log_error("Could not create single instance mutex: %s (%d)", get_errno_name(rc), rc); goto error_mutex; } if (log_to_file) { if (GetModuleFileName(NULL, filename, sizeof(filename)) == 0) { rc = ERRNO_WINAPI_OFFSET + GetLastError(); log_warn("Could not get module file name: %s (%d)", get_errno_name(rc), rc); } else { i = strlen(filename); if (i < 4) { log_warn("Module file name '%s' is too short", filename); } else { filename[i - 3] = '\0'; string_append(filename, "log", sizeof(filename)); log_file = fopen(filename, "a+"); if (log_file == NULL) { log_warn("Could not open log file '%s'", filename); } else { printf("Logging to '%s'\n", filename); log_set_file(log_file); } } } } else if (_run_as_service) { log_set_file(NULL); } if (!_run_as_service && !SetConsoleCtrlHandler(console_ctrl_handler, TRUE)) { rc = ERRNO_WINAPI_OFFSET + GetLastError(); log_warn("Could not set console control handler: %s (%d)", get_errno_name(rc), rc); } log_set_debug_override(debug); log_set_level(LOG_CATEGORY_EVENT, config_get_option("log_level.event")->value.log_level); log_set_level(LOG_CATEGORY_USB, config_get_option("log_level.usb")->value.log_level); log_set_level(LOG_CATEGORY_NETWORK, config_get_option("log_level.network")->value.log_level); log_set_level(LOG_CATEGORY_HOTPLUG, config_get_option("log_level.hotplug")->value.log_level); log_set_level(LOG_CATEGORY_HARDWARE, config_get_option("log_level.hardware")->value.log_level); log_set_level(LOG_CATEGORY_WEBSOCKET, config_get_option("log_level.websocket")->value.log_level); log_set_level(LOG_CATEGORY_OTHER, config_get_option("log_level.other")->value.log_level); if (config_has_error()) { log_error("Error(s) in config file '%s', run with --check-config option for details", _config_filename); fatal_error = true; goto error_config; } if (_run_as_service) { log_info("Brick Daemon %s started (as service)", VERSION_STRING); } else { log_info("Brick Daemon %s started", VERSION_STRING); } if (config_has_warning()) { log_warn("Warning(s) in config file '%s', run with --check-config option for details", _config_filename); } // initialize service status error_config: error_mutex: if (_run_as_service) { if (service_init(service_control_handler) < 0) { // FIXME: set service_exit_code goto error; } if (!fatal_error) { // service is starting service_set_status(SERVICE_START_PENDING, NO_ERROR); } } if (fatal_error) { goto error; } // initialize WinSock2 if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) { // FIXME: set service_exit_code rc = ERRNO_WINAPI_OFFSET + WSAGetLastError(); log_error("Could not initialize Windows Sockets 2.2: %s (%d)", get_errno_name(rc), rc); goto error_event; } if (event_init() < 0) { // FIXME: set service_exit_code goto error_event; } if (hardware_init() < 0) { // FIXME: set service_exit_code goto error_hardware; } if (usb_init(libusb_debug) < 0) { // FIXME: set service_exit_code goto error_usb; } // create notification pipe if (pipe_create(&_notification_pipe) < 0) { // FIXME: set service_exit_code log_error("Could not create notification pipe: %s (%d)", get_errno_name(errno), errno); goto error_pipe; } if (event_add_source(_notification_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC, EVENT_READ, forward_notifications, NULL) < 0) { // FIXME: set service_exit_code goto error_pipe_add; } // register device notification ZeroMemory(¬ification_filter, sizeof(notification_filter)); notification_filter.dbcc_size = sizeof(notification_filter); notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; notification_filter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; if (_run_as_service) { notification_handle = RegisterDeviceNotification((HANDLE)service_get_status_handle(), ¬ification_filter, DEVICE_NOTIFY_SERVICE_HANDLE); } else { if (message_pump_start() < 0) { // FIXME: set service_exit_code goto error_pipe_add; } notification_handle = RegisterDeviceNotification(_message_pump_hwnd, ¬ification_filter, DEVICE_NOTIFY_WINDOW_HANDLE); } if (notification_handle == NULL) { // FIXME: set service_exit_code rc = ERRNO_WINAPI_OFFSET + GetLastError(); log_error("Could not register for device notification: %s (%d)", get_errno_name(rc), rc); goto error_notification; } if (network_init() < 0) { // FIXME: set service_exit_code goto error_network; } // running if (_run_as_service) { service_set_status(SERVICE_RUNNING, NO_ERROR); } if (event_run(network_cleanup_clients_and_zombies) < 0) { // FIXME: set service_exit_code goto error_run; } exit_code = EXIT_SUCCESS; error_run: network_exit(); error_network: UnregisterDeviceNotification(notification_handle); error_notification: if (!_run_as_service) { message_pump_stop(); } event_remove_source(_notification_pipe.read_end, EVENT_SOURCE_TYPE_GENERIC); error_pipe_add: pipe_destroy(&_notification_pipe); error_pipe: usb_exit(); error_usb: hardware_exit(); error_hardware: event_exit(); error_event: log_info("Brick Daemon %s stopped", VERSION_STRING); error: if (!_run_as_service) { // unregister the console handler before exiting the log. otherwise a // control event might be send to the control handler after the log // is not available anymore and the control handler tries to write a // log messages triggering a crash. this situation could easily be // created by clicking the close button of the command prompt window // while the getch call is waiting for the user to press a key. SetConsoleCtrlHandler(console_ctrl_handler, FALSE); } log_exit(); config_exit(); if (_run_as_service) { // because the service process can be terminated at any time after // entering SERVICE_STOPPED state the mutex is closed beforehand, // even though this creates a tiny time window in which the service // is still running but the mutex is not held anymore if (mutex_handle != NULL) { CloseHandle(mutex_handle); } // service is now stopped service_set_status(SERVICE_STOPPED, service_exit_code); } else { if (_pause_before_exit) { printf("Press any key to exit...\n"); getch(); } if (mutex_handle != NULL) { CloseHandle(mutex_handle); } } return exit_code; }