bud_error_t bud_config_reload(bud_config_t* config) { bud_error_t err; bud_config_t* loaded; bud_config_t restore; loaded = bud_config_load(config->path, config->inlined, &err); if (!bud_is_ok(err)) return err; memset(&restore, 0, sizeof(restore)); bud_config_copy(&restore, config); bud_config_copy(config, loaded); /* Initialize config with new params */ err = bud_config_init(config); /* Restore everything on failure */ if (!bud_is_ok(err)) { bud_config_copy(config, &restore); bud_config_free(loaded); return err; } free(loaded); bud_config_destroy(&restore); return bud_ok(); }
bud_error_t bud_config_load(bud_config_t* config) { int i; bud_error_t err; JSON_Value* json; JSON_Value* val; JSON_Object* frontend; JSON_Object* obj; JSON_Object* log; JSON_Object* avail; JSON_Array* contexts; if (config->piped) { char* content; ASSERT(config->loop != NULL, "Loop should be present"); err = bud_read_file_by_fd(config->loop, 0, &content); if (!bud_is_ok(err)) goto end; err = bud_hashmap_insert(&config->files.hashmap, kPipedConfigPath, strlen(kPipedConfigPath), content); if (!bud_is_ok(err)) { free(content); goto end; } json = json_parse_string(content); } else if (config->inlined) { json = json_parse_string(config->path); } else { const char* contents; err = bud_config_load_file(config, config->path, &contents); if (!bud_is_ok(err)) goto end; json = json_parse_string(contents); } if (json == NULL) { err = bud_error_dstr(kBudErrJSONParse, config->path); goto end; } obj = json_value_get_object(json); if (obj == NULL) { err = bud_error(kBudErrJSONNonObjectRoot); goto failed_alloc_path; } err = bud_config_load_tracing(&config->trace, json_object_get_object(obj, "tracing")); if (!bud_is_ok(err)) goto failed_alloc_path; /* Allocate contexts and backends */ contexts = json_object_get_array(obj, "contexts"); config->context_count = contexts == NULL ? 0 : json_array_get_count(contexts); config->contexts = calloc(config->context_count + 1, sizeof(*config->contexts)); if (config->contexts == NULL) { err = bud_error_str(kBudErrNoMem, "bud_context_t"); goto failed_alloc_contexts; } config->json = json; /* Workers configuration */ config->worker_count = -1; config->restart_timeout = -1; config->master_ipc = -1; val = json_object_get_value(obj, "workers"); if (val != NULL) config->worker_count = json_value_get_number(val); val = json_object_get_value(obj, "restart_timeout"); if (val != NULL) config->restart_timeout = json_value_get_number(val); val = json_object_get_value(obj, "master_ipc"); if (val != NULL) config->master_ipc = json_value_get_boolean(val); /* Logger configuration */ log = json_object_get_object(obj, "log"); config->log.stdio = -1; config->log.syslog = -1; if (log != NULL) { config->log.level = json_object_get_string(log, "level"); config->log.facility = json_object_get_string(log, "facility"); val = json_object_get_value(log, "stdio"); if (val != NULL) config->log.stdio = json_value_get_boolean(val); val = json_object_get_value(log, "syslog"); if (val != NULL) config->log.syslog = json_value_get_boolean(val); } /* Availability configuration */ avail = json_object_get_object(obj, "availability"); config->availability.death_timeout = -1; config->availability.revive_interval = -1; config->availability.retry_interval = -1; config->availability.max_retries = -1; if (avail != NULL) { val = json_object_get_value(avail, "death_timeout"); if (val != NULL) config->availability.death_timeout = json_value_get_number(val); val = json_object_get_value(avail, "revive_interval"); if (val != NULL) config->availability.revive_interval = json_value_get_number(val); val = json_object_get_value(avail, "retry_interval"); if (val != NULL) config->availability.retry_interval = json_value_get_number(val); val = json_object_get_value(avail, "max_retries"); if (val != NULL) config->availability.max_retries = json_value_get_number(val); } /* Frontend configuration */ frontend = json_object_get_object(obj, "frontend"); err = bud_config_load_frontend(frontend, &config->frontend); if (!bud_is_ok(err)) goto failed_alloc_contexts; /* Load frontend's context */ err = bud_context_load(frontend, &config->contexts[0]); if (!bud_is_ok(err)) goto failed_alloc_contexts; /* Backend configuration */ config->balance = json_object_get_string(obj, "balance"); err = bud_config_load_backend_list(config, obj, &config->contexts[0].backend); if (!bud_is_ok(err)) goto failed_alloc_contexts; /* User and group configuration */ config->user = json_object_get_string(obj, "user"); config->group = json_object_get_string(obj, "group"); /* SNI configuration */ bud_config_read_pool_conf(obj, "sni", &config->sni); /* OCSP Stapling configuration */ bud_config_read_pool_conf(obj, "stapling", &config->stapling); /* SSL Contexts */ /* TODO(indutny): sort them and do binary search */ for (i = 0; i < config->context_count; i++) { bud_context_t* ctx; /* NOTE: contexts[0] - is a default context */ ctx = &config->contexts[i + 1]; obj = json_array_get_object(contexts, i); if (obj == NULL) { err = bud_error(kBudErrJSONNonObjectCtx); goto failed_load_context; } err = bud_context_load(obj, ctx); if (!bud_is_ok(err)) goto failed_load_context; err = bud_config_load_backend_list(config, obj, &ctx->backend); if (!bud_is_ok(err)) goto failed_load_context; } bud_config_set_defaults(config); return bud_config_init(config); failed_load_context: /* Deinitalize contexts */ for (i++; i >= 0; i--) { bud_context_t* ctx; ctx = &config->contexts[i]; free(ctx->backend.list); ctx->backend.list = NULL; } failed_alloc_contexts: free(config->contexts); config->contexts = NULL; free(config->trace.dso); config->trace.dso = NULL; failed_alloc_path: json_value_free(json); config->json = NULL; end: return err; }
bud_config_t* bud_config_cli_load(uv_loop_t* loop, int argc, char** argv, bud_error_t* err) { int c; int r; int index; int is_daemon; int is_worker; size_t path_len; bud_config_t* config; struct option long_options[] = { { "version", 0, NULL, 'v' }, { "config", 1, NULL, 'c' }, #ifndef _WIN32 { "daemonize", 0, NULL, 'd' }, #endif /* !_WIN32 */ { "worker", 0, NULL, 1000 }, { "default-config", 0, NULL, 1001 }, { NULL, 0, NULL, 0 } }; *err = bud_ok(); config = NULL; is_daemon = 0; is_worker = 0; do { index = 0; c = getopt_long(argc, argv, "vc:d", long_options, &index); switch (c) { case 'v': bud_print_version(); break; case 'c': config = bud_config_load(loop,optarg, err); if (config == NULL) { ASSERT(!bud_is_ok(*err), "Config load failed without error"); c = -1; break; } if (is_daemon) config->is_daemon = 1; if (is_worker) config->is_worker = 1; break; #ifndef _WIN32 case 'd': is_daemon = 1; if (config != NULL) config->is_daemon = 1; #endif /* !_WIN32 */ break; case 1000: is_worker = 1; if (config != NULL) config->is_worker = 1; break; case 1001: bud_config_print_default(); c = -1; break; default: if (config == NULL) bud_print_help(argc, argv); c = -1; break; } } while (c != -1); if (config != NULL) { /* CLI options */ config->argc = argc; config->argv = argv; /* Get executable path */ path_len = sizeof(config->exepath); r = uv_exepath(config->exepath, &path_len); ASSERT(path_len < sizeof(config->exepath), "Exepath OOB"); config->exepath[path_len] = 0; if (r != 0) { bud_config_free(config); config = NULL; *err = bud_error_num(kBudErrExePath, r); } /* Initialize config */ *err = bud_config_init(config); if (!bud_is_ok(*err)) { bud_config_free(config); return NULL; } } return config; }