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_error_t bud_sni_from_json(bud_config_t* config, struct json_value_t* json, bud_context_t* ctx) { JSON_Object* obj; JSON_Value* val; const char* cert_str; const char* key_str; const char* pass_str; JSON_Array* cert_strs; JSON_Array* key_strs; JSON_Array* pass_strs; bud_error_t err; cert_str = NULL; key_str = NULL; pass_str = NULL; cert_strs = NULL; key_strs = NULL; pass_strs = NULL; obj = json_value_get_object(json); val = json_object_get_value(obj, "cert"); if (json_value_get_type(val) == JSONString) cert_str = json_value_get_string(val); else cert_strs = json_value_get_array(val); val = json_object_get_value(obj, "key"); if (json_value_get_type(val) == JSONString) key_str = json_value_get_string(val); else key_strs = json_value_get_array(val); val = json_object_get_value(obj, "passphrase"); if (json_value_get_type(val) == JSONString) pass_str = json_value_get_string(val); else pass_strs = json_value_get_array(val); if (obj == NULL || !((cert_str != NULL && key_str != NULL) || (cert_strs != NULL && key_strs != NULL))) { err = bud_error_str(kBudErrJSONParse, "<SNI Response>"); goto fatal; } /* Load NPN from response */ memset(ctx, 0, sizeof(*ctx)); ctx->cert_file = cert_str; ctx->key_file = key_str; ctx->key_pass = pass_str; ctx->cert_files = cert_strs; ctx->key_files = key_strs; ctx->key_passes = pass_strs; 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"); ctx->npn = json_object_get_array(obj, "npn"); ctx->ca_array = json_object_get_array(obj, "ca"); val = json_object_get_value(obj, "request_cert"); if (val != NULL) ctx->request_cert = json_value_get_boolean(val); err = bud_config_load_backend_list(config, obj, &ctx->backend); if (!bud_is_ok(err)) goto fatal; err = bud_context_init(config, ctx); /* Make sure that deallocated values won't be used */ ctx->cert_file = NULL; ctx->key_file = NULL; ctx->key_pass = NULL; ctx->cert_files = NULL; ctx->key_files = NULL; ctx->key_passes = NULL; if (!bud_is_ok(err)) goto fatal; return bud_ok(); fatal: if (!bud_is_ok(err)) { SSL_CTX_free(ctx->ctx); ctx->ctx = NULL; } free(ctx->backend.list); ctx->backend.list = NULL; return err; }