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_load(const char* path, int inlined, bud_error_t* err) { int i; JSON_Value* json; JSON_Value* val; JSON_Object* obj; JSON_Object* tmp; JSON_Object* log; JSON_Object* avail; JSON_Array* contexts; JSON_Array* backend; bud_config_t* config; bud_context_t* ctx; if (inlined) json = json_parse_string(path); else json = json_parse_file(path); if (json == NULL) { *err = bud_error_str(kBudErrJSONParse, path); goto end; } obj = json_value_get_object(json); if (obj == NULL) { *err = bud_error(kBudErrJSONNonObjectRoot); goto failed_get_object; } config = calloc(1, sizeof(*config)); if (config == NULL) { *err = bud_error_str(kBudErrNoMem, "bud_config_t"); goto failed_get_object; } /* Copy path or inlined config value */ config->path = strdup(path); if (config->path == NULL) { *err = bud_error_str(kBudErrNoMem, "bud_config_t strcpy(path)"); goto failed_alloc_path; } config->inlined = inlined; /* Allocate contexts and backends */ contexts = json_object_get_array(obj, "contexts"); backend = json_object_get_array(obj, "backend"); config->context_count = contexts == NULL ? 0 : json_array_get_count(contexts); config->backend_count = backend == NULL ? 0 : json_array_get_count(backend); config->contexts = calloc(config->context_count + 1, sizeof(*config->contexts)); config->backend = calloc(config->backend_count, sizeof(*config->backend)); if (config->contexts == NULL || config->backend == NULL) { *err = bud_error_str(kBudErrNoMem, "bud_context_t"); goto failed_get_index; } config->json = json; /* Workers configuration */ config->worker_count = -1; config->restart_timeout = -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); /* 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 */ *err = bud_config_load_frontend(json_object_get_object(obj, "frontend"), &config->frontend); if (!bud_is_ok(*err)) goto failed_get_index; /* Backend configuration */ config->balance = json_object_get_string(obj, "balance"); for (i = 0; i < config->backend_count; i++) { bud_config_load_backend(config, json_array_get_object(backend, i), &config->backend[i]); } /* 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++) { /* 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_get_index; } ctx->servername = json_object_get_string(obj, "servername"); ctx->servername_len = ctx->servername == NULL ? 0 : strlen(ctx->servername); ctx->cert_file = json_object_get_string(obj, "cert"); ctx->key_file = json_object_get_string(obj, "key"); ctx->npn = json_object_get_array(obj, "npn"); ctx->ciphers = json_object_get_string(obj, "ciphers"); ctx->ecdh = json_object_get_string(obj, "ecdh"); ctx->ticket_key = json_object_get_string(obj, "ticket_key"); tmp = json_object_get_object(obj, "backend"); if (tmp != NULL) { ctx->backend = &ctx->backend_st; bud_config_load_backend(config, tmp, ctx->backend); } *err = bud_config_verify_npn(ctx->npn); if (!bud_is_ok(*err)) goto failed_get_index; } bud_config_set_defaults(config); *err = bud_ok(); return config; failed_get_index: free(config->contexts); config->contexts = NULL; free(config->backend); config->backend = NULL; free(config->path); config->path = NULL; failed_alloc_path: free(config); failed_get_object: json_value_free(json); end: return NULL; }