/** Reads the configuration file and then starts the main loop */ int main(int argc, char **argv) { s_config *config = config_get_config(); config_init(); parse_commandline(argc, argv); /* Initialize the config */ config_read(config->configfile); config_validate(); /* Initializes the linked list of connected clients */ client_list_init(); /* Init the signals to catch chld/quit/etc */ init_signals(); if (restart_orig_pid) { /* * We were restarted and our parent is waiting for us to talk to it over the socket */ get_clients_from_parent(); /* * At this point the parent will start destroying itself and the firewall. Let it finish it's job before we continue */ while (kill(restart_orig_pid, 0) != -1) { debug(LOG_INFO, "Waiting for parent PID %d to die before continuing loading", restart_orig_pid); sleep(1); } debug(LOG_INFO, "Parent PID %d seems to be dead. Continuing loading."); } if (config->daemon) { debug(LOG_INFO, "Forking into background"); switch(safe_fork()) { case 0: /* child */ setsid(); append_x_restartargv(); main_loop(); break; default: /* parent */ exit(0); break; } } else { append_x_restartargv(); main_loop(); } return(0); /* never reached */ }
int setup(struct config_t *config, int argc, char **argv) { char *home, *cfgfile = NULL; config_init(config); /* parse arguments */ if (parse_args(config, argc, argv) != 0) return SETUP_ERROR; /* if the user did not supply an alternate config file, * check if the default config file exists */ if (!config->filename) { if ((home = getenv("HOME"))) { cfgfile = malloc(strlen(home) + sizeof(CONFIG_FILE) + 2); if (!cfgfile) { warn("malloc failed for $HOME + " CONFIG_FILE); return SETUP_ERROR; } stpcpy(stpcpy(stpcpy(cfgfile, home), "/"), CONFIG_FILE); if (access(cfgfile, F_OK) == 0) { /* file exists - keep malloc'ed data */ config->filename = cfgfile; } else { /* file does not exist - free data */ errno = 0; free(cfgfile); cfgfile = NULL; } } } /* parse config file - if provided or default exists */ if (config->filename && parse_conf(config, config->filename) != 0) return SETUP_ERROR; /* put defaults for each undefined variable */ config_finalize(config); /* check mandatory/conflicting settings */ if (config_validate(config) != 0) return SETUP_ERROR; return SETUP_OK; }
/** Main entry point for nodogsplash. * Reads the configuration file and then starts the main loop. */ int main(int argc, char **argv) { s_config *config = config_get_config(); config_init(); parse_commandline(argc, argv); /* Initialize the config */ debug(LOG_NOTICE,"Reading and validating configuration file %s", config->configfile); config_read(config->configfile); config_validate(); /* Initializes the linked list of connected clients */ client_list_init(); /* Init the signals to catch chld/quit/etc */ debug(LOG_NOTICE,"Initializing signal handlers"); init_signals(); if (config->daemon) { debug(LOG_NOTICE, "Starting as daemon, forking to background"); switch(safe_fork()) { case 0: /* child */ setsid(); main_loop(); break; default: /* parent */ exit(0); break; } } else { main_loop(); } return(0); /* never reached */ }
void vUiTask( void * pvParameters) { lcd_s_reset(); // int_lcd_timer_dec = 1; #ifdef DEBUG_BUILD #else led_update(); printf_P(PSTR("DG1YFE")); lcd_fill(); lcd_cpos(0); printf_P(PSTR("MCmega")); lcd_fill(); lcd_cpos(0); vTaskDelay(150); printf_P(version_str); lcd_fill(); vTaskDelay(150); // reset_ui(UI_RESET_WARM); #endif reset_ui(UI_RESET_COLD); for(;;) { pll_led(0); led_update(); menu(); taskYIELD(); // check if reset of control head was detected // (certain amount of 0x7e reset messages was received) if(!ch_reset_detected) { lcd_s_reset(); reset_ui(UI_RESET_COLD); } config_validate(); } }
/** * \brief Program main function. * \param argc Argument count from commandline * \param argv Argument list * \return Program exit state */ int main(int argc, char *argv[]) { config *cfg = NULL; //!< Global configuration FILE *input = NULL; //!< input file (YUV) FILE *output = NULL; //!< output file (HEVC NAL stream) encoder_control encoder; double psnr[3] = { 0.0, 0.0, 0.0 }; uint32_t stat_frames = 0; uint64_t curpos = 0; FILE *recout = NULL; //!< reconstructed YUV output, --debug clock_t start_time = clock(); clock_t encoding_start_cpu_time; CLOCK_T encoding_start_real_time; clock_t encoding_end_cpu_time; CLOCK_T encoding_end_real_time; // Stdin and stdout need to be binary for input and output to work. // Stderr needs to be text mode to convert \n to \r\n in Windows. #ifdef _WIN32 _setmode( _fileno( stdin ), _O_BINARY ); _setmode( _fileno( stdout ), _O_BINARY ); _setmode( _fileno( stderr ), _O_TEXT ); #endif CHECKPOINTS_INIT(); // Handle configuration cfg = config_alloc(); // If problem with configuration, print banner and shutdown if (!cfg || !config_init(cfg) || !config_read(cfg,argc,argv)) { fprintf(stderr, "/***********************************************/\n" " * Kvazaar HEVC Encoder v. " VERSION_STRING " *\n" " * Tampere University of Technology 2014 *\n" "/***********************************************/\n\n"); fprintf(stderr, "Usage:\n" "kvazaar -i <input> --input-res <width>x<height> -o <output>\n" "\n" "Optional parameters:\n" " -n, --frames <integer> : Number of frames to code [all]\n" " --seek <integer> : First frame to code [0]\n" " --input-res <int>x<int> : Input resolution (width x height)\n" " -q, --qp <integer> : Quantization Parameter [32]\n" " -p, --period <integer> : Period of intra pictures [0]\n" " 0: only first picture is intra\n" " 1: all pictures are intra\n" " 2-N: every Nth picture is intra\n" " -r, --ref <integer> : Reference frames, range 1..15 [3]\n" " --no-deblock : Disable deblocking filter\n" " --deblock <beta:tc> : Deblocking filter parameters\n" " beta and tc range is -6..6 [0:0]\n" " --no-sao : Disable sample adaptive offset\n" " --no-rdoq : Disable RDO quantization\n" " --rd <integer> : Rate-Distortion Optimization level [1]\n" " 0: no RDO\n" " 1: estimated RDO\n" " 2: full RDO\n" " --full-intra-search : Try all intra modes.\n" " --no-transform-skip : Disable transform skip\n" " --aud : Use access unit delimiters\n" " --cqmfile <string> : Custom Quantization Matrices from a file\n" " --debug <string> : Output encoders reconstruction.\n" " --cpuid <integer> : Disable runtime cpu optimizations with value 0.\n" "\n" " Video Usability Information:\n" " --sar <width:height> : Specify Sample Aspect Ratio\n" " --overscan <string> : Specify crop overscan setting [\"undef\"]\n" " - undef, show, crop\n" " --videoformat <string> : Specify video format [\"undef\"]\n" " - component, pal, ntsc, secam, mac, undef\n" " --range <string> : Specify color range [\"tv\"]\n" " - tv, pc\n" " --colorprim <string> : Specify color primaries [\"undef\"]\n" " - undef, bt709, bt470m, bt470bg,\n" " smpte170m, smpte240m, film, bt2020\n" " --transfer <string> : Specify transfer characteristics [\"undef\"]\n" " - undef, bt709, bt470m, bt470bg,\n" " smpte170m, smpte240m, linear, log100,\n" " log316, iec61966-2-4, bt1361e,\n" " iec61966-2-1, bt2020-10, bt2020-12\n" " --colormatrix <string> : Specify color matrix setting [\"undef\"]\n" " - undef, bt709, fcc, bt470bg, smpte170m,\n" " smpte240m, GBR, YCgCo, bt2020nc, bt2020c\n" " --chromaloc <integer> : Specify chroma sample location (0 to 5) [0]\n" "\n" " Parallel processing :\n" " --threads <integer> : Maximum number of threads to use.\n" " Disable threads if set to 0.\n" "\n" " Tiles:\n" " --tiles-width-split <string>|u<int> : \n" " Specifies a comma separated list of pixel\n" " positions of tiles columns separation coordinates.\n" " Can also be u followed by and a single int n,\n" " in which case it produces columns of uniform width.\n" " --tiles-height-split <string>|u<int> : \n" " Specifies a comma separated list of pixel\n" " positions of tiles rows separation coordinates.\n" " Can also be u followed by and a single int n,\n" " in which case it produces rows of uniform height.\n" "\n" " Wpp:\n" " --wpp : Enable wavefront parallel processing\n" " --owf <integer> : Enable parallel processing of multiple frames\n" "\n" " Slices:\n" " --slice-addresses <string>|u<int>: \n" " Specifies a comma separated list of LCU\n" " positions in tile scan order of tile separations.\n" " Can also be u followed by and a single int n,\n" " in which case it produces uniform slice length.\n" "\n" " Deprecated parameters: (might be removed at some point)\n" " Use --input-res:\n" " -w, --width : Width of input in pixels\n" " -h, --height : Height of input in pixels\n"); goto exit_failure; } // Add dimensions to the reconstructions file name. if (cfg->debug != NULL) { char dim_str[50]; // log10(2^64) < 20, so this should suffice. I hate C. size_t left_len, right_len; sprintf(dim_str, "_%dx%d.yuv", cfg->width, cfg->height); left_len = strlen(cfg->debug); right_len = strlen(dim_str); cfg->debug = realloc(cfg->debug, left_len + right_len + 1); if (!cfg->debug) { fprintf(stderr, "realloc failed!\n"); goto exit_failure; } strcpy(cfg->debug + left_len, dim_str); } // Do more validation to make sure the parameters we have make sense. if (!config_validate(cfg)) { goto exit_failure; } //Initialize strategies if (!strategyselector_init(cfg->cpuid)) { fprintf(stderr, "Failed to initialize strategies.\n"); goto exit_failure; } // Check if the input file name is a dash, this means stdin if (!strcmp(cfg->input, "-")) { input = stdin; } else { // Otherwise we try to open the input file input = fopen(cfg->input, "rb"); } // Check that input was opened correctly if (input == NULL) { fprintf(stderr, "Could not open input file, shutting down!\n"); goto exit_failure; } // Open output file and check that it was opened correctly output = fopen(cfg->output, "wb"); if (output == NULL) { fprintf(stderr, "Could not open output file, shutting down!\n"); goto exit_failure; } if (cfg->debug != NULL) { recout = fopen(cfg->debug, "wb"); if (recout == NULL) { fprintf(stderr, "Could not open reconstruction file (%s), shutting down!\n", cfg->debug); goto exit_failure; } } //Allocate and init exp golomb table if (!init_exp_golomb(4096*8)) { fprintf(stderr, "Failed to allocate the exp golomb code table, shutting down!\n"); goto exit_failure; } if (!encoder_control_init(&encoder, cfg)) { goto exit_failure; } // Set output file encoder.out.file = output; // input init (TODO: read from commandline / config) encoder.bitdepth = 8; encoder.in.video_format = FORMAT_420; // deblocking filter encoder.deblock_enable = (int8_t)encoder.cfg->deblock_enable; encoder.beta_offset_div2 = (int8_t)encoder.cfg->deblock_beta; encoder.tc_offset_div2 = (int8_t)encoder.cfg->deblock_tc; // SAO encoder.sao_enable = (int8_t)encoder.cfg->sao_enable; // RDO encoder.rdoq_enable = (int8_t)encoder.cfg->rdoq_enable; encoder.rdo = (int8_t)encoder.cfg->rdo; encoder.full_intra_search = (int8_t)encoder.cfg->full_intra_search; // TR SKIP encoder.trskip_enable = (int8_t)encoder.cfg->trskip_enable; encoder.tr_depth_intra = (int8_t)encoder.cfg->tr_depth_intra; // VUI encoder.vui.sar_width = (int16_t)encoder.cfg->vui.sar_width; encoder.vui.sar_height = (int16_t)encoder.cfg->vui.sar_height; encoder.vui.overscan = encoder.cfg->vui.overscan; encoder.vui.videoformat = encoder.cfg->vui.videoformat; encoder.vui.fullrange = encoder.cfg->vui.fullrange; encoder.vui.colorprim = encoder.cfg->vui.colorprim; encoder.vui.transfer = encoder.cfg->vui.transfer; encoder.vui.colormatrix = encoder.cfg->vui.colormatrix; encoder.vui.chroma_loc = (int8_t)encoder.cfg->vui.chroma_loc; // AUD encoder.aud_enable = (int8_t)encoder.cfg->aud_enable; encoder.in.file = input; fprintf(stderr, "Input: %s, output: %s\n", cfg->input, cfg->output); fprintf(stderr, " Video size: %dx%d (input=%dx%d)\n", encoder.in.width, encoder.in.height, encoder.in.real_width, encoder.in.real_height); //Now, do the real stuff { encoder_state *encoder_states = malloc((encoder.owf + 1) * sizeof(encoder_state)); if (encoder_states == NULL) { fprintf(stderr, "Failed to allocate memory."); goto exit_failure; } int i; int current_encoder_state = 0; for (i = 0; i <= encoder.owf; ++i) { encoder_states[i].encoder_control = &encoder; if (i > 0) { encoder_states[i].previous_encoder_state = &encoder_states[i-1]; } else { //i == 0, use last encoder as the previous one encoder_states[i].previous_encoder_state = &encoder_states[encoder.owf]; } if (!encoder_state_init(&encoder_states[i], NULL)) { goto exit_failure; } encoder_states[i].global->QP = (int8_t)encoder.cfg->qp; } for (i = 0; i <= encoder.owf; ++i) { encoder_state_match_children_of_previous_frame(&encoder_states[i]); } //Initial frame encoder_states[current_encoder_state].global->frame = -1; // Only the code that handles conformance window coding needs to know // the real dimensions. As a quick fix for broken non-multiple of 8 videos, // change the input values here to be the real values. For a real fix // encoder.in probably needs to be merged into cfg. // The real fix would be: never go dig in cfg //cfg->width = encoder.in.width; //cfg->height = encoder.in.height; GET_TIME(&encoding_start_real_time); encoding_start_cpu_time = clock(); // Start coding cycle while data on input and not on the last frame while(!cfg->frames || encoder_states[current_encoder_state].global->frame < cfg->frames - 1) { // Skip '--seek' frames before input. // This block can be moved outside this while loop when there is a // mechanism to skip the while loop on error. if (encoder_states[current_encoder_state].global->frame == 0 && cfg->seek > 0) { int frame_bytes = cfg->width * cfg->height * 3 / 2; int error = 0; if (!strcmp(cfg->input, "-")) { // Input is stdin. int i; for (i = 0; !error && i < cfg->seek; ++i) { error = !read_one_frame(input, &encoder_states[current_encoder_state]); } } else { // input is a file. We hope. Proper detection is OS dependent. error = fseek(input, cfg->seek * frame_bytes, SEEK_CUR); } if (error && !feof(input)) { fprintf(stderr, "Failed to seek %d frames.\n", cfg->seek); break; } GET_TIME(&encoding_start_real_time); encoding_start_cpu_time = clock(); } //Compute stats encoder_compute_stats(&encoder_states[current_encoder_state], recout, &stat_frames, psnr); //Clear encoder encoder_next_frame(&encoder_states[current_encoder_state]); //Abort if enough frames if (cfg->frames && encoder_states[current_encoder_state].global->frame >= cfg->frames) { //Ignore this frame, which is not valid... encoder_states[current_encoder_state].stats_done = 1; break; } CHECKPOINT_MARK("read source frame: %d", encoder_states[current_encoder_state].global->frame + cfg->seek); // Read one frame from the input if (!read_one_frame(input, &encoder_states[current_encoder_state])) { if (!feof(input)) fprintf(stderr, "Failed to read a frame %d\n", encoder_states[current_encoder_state].global->frame); //Ignore this frame, which is not valid... encoder_states[current_encoder_state].stats_done = 1; break; } // The actual coding happens here, after this function we have a coded frame encode_one_frame(&encoder_states[current_encoder_state]); //Switch to the next encoder current_encoder_state = (current_encoder_state + 1) % (encoder.owf + 1); } //Compute stats for the remaining encoders { int first_enc = current_encoder_state; do { current_encoder_state = (current_encoder_state + 1) % (encoder.owf + 1); encoder_compute_stats(&encoder_states[current_encoder_state], recout, &stat_frames, psnr); } while (current_encoder_state != first_enc); } GET_TIME(&encoding_end_real_time); encoding_end_cpu_time = clock(); threadqueue_flush(encoder.threadqueue); // Coding finished fgetpos(output,(fpos_t*)&curpos); // Print statistics of the coding fprintf(stderr, " Processed %d frames, %10llu bits AVG PSNR: %2.4f %2.4f %2.4f\n", stat_frames, (long long unsigned int) curpos<<3, psnr[0] / stat_frames, psnr[1] / stat_frames, psnr[2] / stat_frames); fprintf(stderr, " Total CPU time: %.3f s.\n", ((float)(clock() - start_time)) / CLOCKS_PER_SEC); { double encoding_time = ((double)(encoding_end_cpu_time - encoding_start_cpu_time)) / CLOCKS_PER_SEC; double wall_time = CLOCK_T_AS_DOUBLE(encoding_end_real_time) - CLOCK_T_AS_DOUBLE(encoding_start_real_time); fprintf(stderr, " Encoding time: %.3lf s.\n", encoding_time); fprintf(stderr, " Encoding wall time: %.3lf s.\n", wall_time); fprintf(stderr, " Encoding CPU usage: %.2lf%%\n", encoding_time/wall_time*100.f); fprintf(stderr, " FPS: %.2lf\n", ((double)stat_frames)/wall_time); } fclose(input); fclose(output); if(recout != NULL) fclose(recout); for (i = 0; i <= encoder.owf; ++i) { encoder_state_finalize(&encoder_states[i]); } free(encoder_states); } // Deallocating config_destroy(cfg); encoder_control_finalize(&encoder); free_exp_golomb(); strategyselector_free(); CHECKPOINTS_FINALIZE(); return EXIT_SUCCESS; exit_failure: if (cfg) config_destroy(cfg); if (input) fclose(input); if (output) fclose(output); if (recout) fclose(recout); strategyselector_free(); CHECKPOINTS_FINALIZE(); return EXIT_FAILURE; }
/************************************************************* ** MAIN ** Reads the config file. Binds to a port. Launches the ** worker and other threads. Listens for requests. */ int main(int argc, char **argv) { char * conf = NULL; int nthreads; int c, ret; char** ary; char* prog; u_int numfds = 0; int xerror; int bg_flag = TRUE; int only_check_config; char ebuf[BUFSIZ]; char nbuf[64]; u_char * gifimage = NULL; u_char * favicon = NULL; int gifimagelen = 0; int faviconlen = 0; TPOOL_CTX * tpool_ctx = NULL; DEBUGS * dp; LISTEN_CTX *gctx = NULL; LISTEN_CTX *dctx = NULL; LISTEN_CTX *jctx = NULL; pthread_t gif_tid; pthread_t data_tid; pthread_t upload_tid; #if HAVE_RESOURCE_H || HAVE_SYS_RESOURCE_H struct rlimit rl; #endif time_t servertimeout; prog = basename(argv[0]); if (prog == NULL) prog = argv[0]; only_check_config = FALSE; servertimeout = 20; while ((c = getopt(argc, argv, "C:d:c:f")) != -1) { switch (c) { case 'f': bg_flag = FALSE; break; case 'C': only_check_config = TRUE; /*FALLTHROUGH*/ case 'c': conf = optarg; break; case 'd': /* * Debugging turned of if in background */ if (bg_flag == TRUE) break; for (dp = DebugNames; dp->name != NULL; dp++) { if (strncasecmp(dp->name, optarg, strlen(optarg)) == 0) { setdebug(dp->flag); if (dp->flag == BUG_THREADS || dp->flag == BUG_ALL) tpool_debug_set(TRUE); break; } } if (dp->name != NULL) break; printf("Unknown debug flag: %s, select from:\n", optarg); for (dp = DebugNames; dp->name != NULL; dp++) printf("\t%s\n", dp->name); return 0; case '?': default: usage: printf("Usage: %s " "[-c /path/onepixd.conf " "or " "-C /path/onepixd.conf] " "-d what " "[-f]\n", prog); return 0; } } if (argc != optind) goto usage; if (conf == NULL || strlen(conf) == 0) { (void) fprintf(stderr, "Required Parameter \"-c configfile\" missing.\n"); goto usage; } ret = config_read_file(conf); if (ret != 0) return 0; /* * All errors are logged, so we need to set up * logging before checking the config file. */ ary = config_lookup(CONF_LOG_FACILITY); if (ary == NULL) ret = log_init(DEFAULT_LOG_FACILITY, prog); else ret = log_init(ary[0], prog); if (ret != 0) return 0; ret = config_validate(); if (ret != 0) return 0; if (ret == 0 && only_check_config == TRUE) (void) printf("%s: FILE IS OKAY TO USE\n", conf); if (only_check_config == TRUE) return 0; ary = config_lookup(CONF_HOME_DIR); if (ary != NULL) { if (chdir(ary[0]) != 0) { xerror = errno; (void) snprintf(ebuf, sizeof ebuf, "Attempt to chdir(\"%s\"): %s", ary[0], strerror(xerror)); log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf); goto shutdown_server; } } if (util_bg(bg_flag) != 0) { (void) snprintf(ebuf, sizeof ebuf, "fork(): %s\n", strerror(errno)); log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf); goto shutdown_server; } #if HAVE_RESOURCE_H || HAVE_SYS_RESOURCE_H #ifdef RLIMIT_AS rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_AS, &rl); /* max size virtual memory */ #endif #ifdef RLIMIT_CPU rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_CPU, &rl); /* unlimited CPU usage */ #endif #ifdef RLIMIT_DATA rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_DATA, &rl); /* unlimited memory */ #endif #ifdef RLIMIT_FSIZE rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_FSIZE, &rl); /* unlimited file sizes */ #endif #ifdef RLIMIT_STACK rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_STACK, &rl); /* unlimited stack */ #endif #ifdef RLIMIT_CORE rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_CORE, &rl); /* allow core dumps */ #endif #ifdef RLIMIT_NOFILE rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_NOFILE, &rl); /* maximum file descriptors */ (void) getrlimit(RLIMIT_NOFILE, &rl); numfds = (rl.rlim_cur); #endif #endif /* HAVE_RESOURCE_H */ ary = config_lookup(CONF_BECOME_USER); if (ary != NULL) { /* * Note that setrunasuser() logs its own errors */ if (setrunasuser(ary[0]) != 0) goto shutdown_server; } ary = config_lookup(CONF_NUMTHREADS); if (ary == NULL) nthreads = DEFAULT_THREADS; else { nthreads = strtoul(ary[0], NULL, 10); if (nthreads <= 0) { (void) fprintf(stderr, "Configuration item \"%s\" illegal value: %d.\n", CONF_NUMTHREADS, nthreads); return 0; } } if (numfds == 0 || numfds > (nthreads * 3)) numfds = nthreads * 3; (void) io_init(numfds); gifimage = gif_get1x1gif(&gifimagelen); if (gifimage == NULL) { (void) snprintf(ebuf, sizeof ebuf, "Load gif image: %s\n", strerror(errno)); log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf); goto shutdown_server; } favicon = gif_getfavicon_ico(&faviconlen); /* * Prepare to launch the thread to listen for inbound * gif requests. */ gctx = str_alloc(sizeof(LISTEN_CTX), 1, __FILE__, __LINE__); if (gctx == NULL) { (void) snprintf(ebuf, sizeof ebuf, "alloc(): %s\n", strerror(errno)); log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf); goto shutdown_server; } gctx->type = LISTEN_TYPE_GIF; /* gif image only, no favicon */ gctx->gifimage = gifimage; gctx->gifimagelen = gifimagelen; gctx->favicon = NULL; gctx->faviconlen = 0; ary = config_lookup(CONF_GIF_PORT); if (ary == NULL) (void) strlcpy(gctx->port, "80", sizeof gctx->port); else (void) strlcpy(gctx->port, ary[0], sizeof gctx->port); ary = config_lookup(CONF_GIF_INTERFACE); if (ary == NULL) (void) strlcpy(gctx->interface, "INADDR_ANY", sizeof gctx->interface); else (void) strlcpy(gctx->interface, ary[0], sizeof gctx->interface); /* * Everything from here down must be thread safe. */ tpool_ctx = tpool_init(nthreads, ebuf, sizeof ebuf); if (tpool_ctx == NULL) goto shutdown_server; gctx->tpool_ctx = tpool_ctx; /* * The GIF server may have to bind to a privaliged port, such * as port 80, so we launch it and expect it to change the * user id after its bind. */ ret = pthread_create(&gif_tid, NULL, thread_listener, (void *)gctx); if (ret != 0) { } /* * Prepare to launch the thread to listen for inbound * data requests. */ dctx = str_alloc(sizeof(LISTEN_CTX), 1, __FILE__, __LINE__); if (dctx == NULL) { (void) snprintf(ebuf, sizeof ebuf, "alloc(): %s\n", strerror(errno)); log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf); goto shutdown_server; } dctx->type = LISTEN_TYPE_DATA; /* a favicon only, no gif */ dctx->gifimage = NULL; dctx->favicon = favicon; dctx->gifimagelen = 0; dctx->faviconlen = faviconlen; ary = config_lookup(CONF_DATA_PORT); if (ary == NULL) (void) strlcpy(dctx->port, "8100", sizeof dctx->port); else (void) strlcpy(dctx->port, ary[0], sizeof dctx->port); ary = config_lookup(CONF_DATA_INTERFACE); if (ary == NULL) (void) strlcpy(dctx->interface, "INADDR_ANY", sizeof dctx->interface); else (void) strlcpy(dctx->interface, ary[0], sizeof dctx->interface); dctx->tpool_ctx = tpool_ctx; ret = pthread_create(&data_tid, NULL, thread_listener, (void *)dctx); if (ret != 0) { } /* * Prepare to launch the thread to listen for uploads of more. */ (void) verify_threads_locking_init(); jctx = str_alloc(sizeof(LISTEN_CTX), 1, __FILE__, __LINE__); if (jctx == NULL) { (void) snprintf(ebuf, sizeof ebuf, "alloc(): %s\n", strerror(errno)); log_emit(LOG_ERR, NULL, __FILE__, __LINE__, ebuf); goto shutdown_server; } jctx->type = LISTEN_TYPE_UPLOAD; /* a favicon only, no gif */ jctx->gifimage = NULL; jctx->favicon = favicon; jctx->gifimagelen = 0; jctx->faviconlen = faviconlen; ary = config_lookup(CONF_UPLOAD_PORT); if (ary == NULL) (void) strlcpy(jctx->port, "8101", sizeof jctx->port); else (void) strlcpy(jctx->port, ary[0], sizeof jctx->port); ary = config_lookup(CONF_UPLOAD_INTERFACE); if (ary == NULL) (void) strlcpy(jctx->interface, "INADDR_ANY", sizeof jctx->interface); else (void) strlcpy(jctx->interface, ary[0], sizeof jctx->interface); jctx->tpool_ctx = tpool_ctx; ret = pthread_create(&upload_tid, NULL, thread_listener, (void *)jctx); if (ret != 0) { } ary = config_lookup(CONF_PIDFILE); if (ary != NULL) { /* * Note that write_pid_file() logs its own errors */ if (write_pid_file(ary[0]) != 0) goto shutdown_server; } (void) strlcpy(ebuf, "Startup: version=", sizeof ebuf); (void) strlcat(ebuf, VERSION, sizeof ebuf); (void) strlcat(ebuf, ", gif_interface=", sizeof ebuf); (void) strlcat(ebuf, gctx->interface, sizeof ebuf); (void) strlcat(ebuf, ", gif_port=", sizeof ebuf); (void) strlcat(ebuf, gctx->port, sizeof ebuf); (void) strlcat(ebuf, ", data_interface=", sizeof ebuf); (void) strlcat(ebuf, dctx->interface, sizeof ebuf); (void) strlcat(ebuf, ", data_port=", sizeof ebuf); (void) strlcat(ebuf, dctx->port, sizeof ebuf); (void) strlcat(ebuf, ", threads=", sizeof ebuf); (void) str_ultoa(nthreads, nbuf, sizeof nbuf); (void) strlcat(ebuf, nbuf, sizeof ebuf); log_emit(LOG_INFO, NULL, __FILE__, __LINE__, ebuf); Global_Die = FALSE; (void) signal(SIGINT, catch_sig); (void) signal(SIGQUIT, catch_sig); (void) signal(SIGKILL, catch_sig); (void) signal(SIGTERM, catch_sig); (void) signal(SIGPIPE, SIG_IGN); if (Global_Die == TRUE) goto shutdown_server; (void) file_prune_garbage(&Global_Die); shutdown_server: Global_Die = TRUE; (void) pthread_join(data_tid, NULL); (void) pthread_join(gif_tid, NULL); (void) pthread_join(upload_tid, NULL); (void) verify_threads_locking_shutdown(); if (tpool_ctx != NULL) tpool_ctx = tpool_shutdown(tpool_ctx, ebuf, sizeof ebuf); if (gctx != NULL) gctx = str_free(gctx, __FILE__, __LINE__); if (dctx != NULL) dctx = str_free(dctx, __FILE__, __LINE__); if (jctx != NULL) jctx = str_free(jctx, __FILE__, __LINE__); if (gifimage != NULL) gifimage = str_free(gifimage, __FILE__, __LINE__); if (favicon != NULL) favicon = str_free(favicon, __FILE__, __LINE__); ary = config_lookup(CONF_PIDFILE); if (ary != NULL) (void) unlink(ary[0]); io_shutdown(); config_shutdown(); (void) strlcpy(ebuf, "Shutdown: version=", sizeof ebuf); (void) strlcat(ebuf, VERSION, sizeof ebuf); log_emit(LOG_INFO, NULL, __FILE__, __LINE__, ebuf); /* * This str_shutdown must always be last. */ str_shutdown(); return 0; }