Пример #1
0
void bud_config_print_default() {
  bud_config_t config;
  bud_config_backend_t backend;
  bud_context_t context;

  memset(&backend, 0, sizeof(backend));
  memset(&config, 0, sizeof(config));
  memset(&context, 0, sizeof(context));

  /* Set zero-y values */
  config.worker_count = -1;
  config.restart_timeout = -1;
  config.master_ipc = -1;
  config.log.stdio = -1;
  config.log.syslog = -1;
  config.frontend.keepalive = -1;
  config.frontend.max_send_fragment = -1;
  config.frontend.allow_half_open = -1;
  config.availability.death_timeout = -1;
  config.availability.revive_interval = -1;
  config.availability.retry_interval = -1;
  config.availability.max_retries = -1;
  config.context_count = 0;
  config.contexts = &context;
  context.backend.list = &backend;
  context.backend.list[0].keepalive = -1;
  context.backend.count = 1;
  context.ticket_timeout = -1;
  context.ticket_rotate = -1;

  bud_config_set_defaults(&config);

  fprintf(stdout, "{\n");
  fprintf(stdout, "  \"daemon\": false,\n");
  fprintf(stdout, "  \"workers\": %d,\n", config.worker_count);
  fprintf(stdout, "  \"restart_timeout\": %d,\n", config.restart_timeout);
  fprintf(stdout, "  \"master_ipc\": false,\n");
  fprintf(stdout, "  \"log\": {\n");
  fprintf(stdout, "    \"level\": \"%s\",\n", config.log.level);
  fprintf(stdout, "    \"facility\": \"%s\",\n", config.log.facility);
  fprintf(stdout,
          "    \"stdio\": %s,\n",
          config.log.stdio ? "true" : "false");
  fprintf(stdout,
          "    \"syslog\": %s\n",
          config.log.syslog ? "true" : "false");
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"availability\": {\n");
  fprintf(stdout,
      "    \"death_timeout\": %d,\n",
          config.availability.death_timeout);
  fprintf(stdout,
          "    \"revive_interval\": %d,\n",
          config.availability.revive_interval);
  fprintf(stdout,
          "    \"retry_interval\": %d,\n",
          config.availability.retry_interval);
  fprintf(stdout,
          "    \"max_retries\": %d\n",
          config.availability.max_retries);
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"frontend\": {\n");
  fprintf(stdout, "    \"port\": %d,\n", config.frontend.port);
  fprintf(stdout, "    \"host\": \"%s\",\n", config.frontend.host);
  fprintf(stdout, "    \"keepalive\": %d,\n", config.frontend.keepalive);
  fprintf(stdout, "    \"security\": \"%s\",\n", config.frontend.security);
  fprintf(stdout, "    \"server_preference\": true,\n");
  fprintf(stdout,
          "    \"max_send_fragment\": %d,\n",
          config.frontend.max_send_fragment);
  if (config.frontend.allow_half_open)
    fprintf(stdout, "    \"allow_half_open\": true,\n");
  else
    fprintf(stdout, "    \"allow_half_open\": false,\n");
#ifdef OPENSSL_NPN_NEGOTIATED
  /* Sorry, hard-coded */
  fprintf(stdout, "    \"npn\": [\"http/1.1\", \"http/1.0\"],\n");
#endif  /* OPENSSL_NPN_NEGOTIATED */
  if (context.ciphers != NULL)
    fprintf(stdout, "    \"ciphers\": \"%s\",\n", context.ciphers);
  else
    fprintf(stdout, "    \"ciphers\": null,\n");
  if (context.ecdh != NULL)
    fprintf(stdout, "    \"ecdh\": \"%s\",\n", context.ecdh);
  else
    fprintf(stdout, "    \"ecdh\": null,\n");
  if (context.dh_file != NULL)
    fprintf(stdout, "    \"dh\": \"%s\",\n", context.dh_file);
  else
    fprintf(stdout, "    \"dh\": null,\n");
  fprintf(stdout, "    \"cert\": \"%s\",\n", context.cert_file);
  fprintf(stdout, "    \"key\": \"%s\",\n", context.key_file);
  fprintf(stdout, "    \"passphrase\": null,\n");
  fprintf(stdout, "    \"ticket_key\": null,\n");
  fprintf(stdout, "    \"ticket_timeout\": %d,\n", context.ticket_timeout);
  fprintf(stdout, "    \"ticket_rotate\": %d,\n", context.ticket_rotate);
  fprintf(stdout, "    \"request_cert\": false,\n");
  fprintf(stdout, "    \"optional_cert\": false,\n");
  fprintf(stdout, "    \"ca\": null,\n");
  fprintf(stdout, "    \"reneg_window\": %d,\n", config.frontend.reneg_window);
  fprintf(stdout, "    \"reneg_limit\": %d\n", config.frontend.reneg_limit);
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"balance\": \"%s\",\n", config.balance);
  fprintf(stdout, "  \"user\": null,\n");
  fprintf(stdout, "  \"group\": null,\n");
  fprintf(stdout, "  \"backend\": [{\n");
  fprintf(stdout, "    \"port\": %d,\n", context.backend.list[0].port);
  fprintf(stdout, "    \"host\": \"%s\",\n", context.backend.list[0].host);
  fprintf(stdout,
          "    \"keepalive\": %d,\n",
          context.backend.list[0].keepalive);
  fprintf(stdout, "    \"proxyline\": false,\n");
  fprintf(stdout, "    \"x-forward\": false\n");
  fprintf(stdout, "  }],\n");
  fprintf(stdout, "  \"sni\": {\n");
  fprintf(stdout, "    \"enabled\": false,\n");
  fprintf(stdout, "    \"port\": %d,\n", config.sni.port);
  fprintf(stdout, "    \"host\": \"%s\",\n", config.sni.host);
  fprintf(stdout, "    \"url\": \"%s\"\n", config.sni.url);
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"stapling\": {\n");
  fprintf(stdout, "    \"enabled\": false,\n");
  fprintf(stdout, "    \"port\": %d,\n", config.stapling.port);
  fprintf(stdout, "    \"host\": \"%s\",\n", config.stapling.host);
  fprintf(stdout, "    \"url\": \"%s\"\n", config.stapling.url);
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"contexts\": [],\n");
  fprintf(stdout, "  \"tracing\": {\n");
  fprintf(stdout, "    \"dso\": []\n");
  fprintf(stdout, "  }\n");
  fprintf(stdout, "}\n");
}
Пример #2
0
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;
}
Пример #3
0
bud_config_t* bud_config_load(uv_loop_t* loop,
                              const char* path,
                              bud_error_t* err) {
  int i;
  int context_count;
  JSON_Value* json;
  JSON_Value* val;
  JSON_Object* obj;
  JSON_Object* log;
  JSON_Object* frontend;
  JSON_Object* backend;
  JSON_Array* contexts;
  bud_config_t* config;
  bud_context_t* ctx;

  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;
  }
  contexts = json_object_get_array(obj, "contexts");
  context_count = contexts == NULL ? 0 : json_array_get_count(contexts);

  config = calloc(1,
                  sizeof(*config) +
                      context_count * sizeof(*config->contexts));
  if (config == NULL) {
    *err = bud_error_str(kBudErrNoMem, "bud_config_t");
    goto failed_get_object;
  }

  config->loop = loop;
  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);
  }

  /* Frontend configuration */

  frontend = json_object_get_object(obj, "frontend");
  config->frontend.proxyline = -1;
  config->frontend.keepalive = -1;
  config->frontend.server_preference = -1;
  config->frontend.ssl3 = -1;
  if (frontend != NULL) {
    config->frontend.port = (uint16_t) json_object_get_number(frontend, "port");
    config->frontend.host = json_object_get_string(frontend, "host");
    config->frontend.security = json_object_get_string(frontend, "security");
    config->frontend.npn = json_object_get_array(frontend, "npn");
    config->frontend.ciphers = json_object_get_string(frontend, "ciphers");
    config->frontend.cert_file = json_object_get_string(frontend, "cert");
    config->frontend.key_file = json_object_get_string(frontend, "key");
    config->frontend.reneg_window = json_object_get_number(frontend,
                                                           "reneg_window");
    config->frontend.reneg_limit = json_object_get_number(frontend,
                                                          "reneg_limit");

    *err = bud_config_verify_npn(config->frontend.npn);
    if (!bud_is_ok(*err))
      goto failed_get_index;

    val = json_object_get_value(frontend, "proxyline");
    if (val != NULL)
      config->frontend.proxyline = json_value_get_boolean(val);
    val = json_object_get_value(frontend, "keepalive");
    if (val != NULL)
      config->frontend.keepalive = json_value_get_number(val);
    val = json_object_get_value(frontend, "server_preference");
    if (val != NULL)
      config->frontend.server_preference = json_value_get_boolean(val);
    val = json_object_get_value(frontend, "ssl3");
    if (val != NULL)
      config->frontend.ssl3 = json_value_get_boolean(val);
  }

  /* Backend configuration */
  backend = json_object_get_object(obj, "backend");
  config->backend.keepalive = -1;
  if (backend != NULL) {
    config->backend.port = (uint16_t) json_object_get_number(backend, "port");
    config->backend.host = json_object_get_string(backend, "host");
    val = json_object_get_value(backend, "keepalive");
    if (val != NULL)
      config->backend.keepalive = json_value_get_number(val);
  }

  /* 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 < 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");

    *err = bud_config_verify_npn(ctx->npn);
    if (!bud_is_ok(*err))
      goto failed_get_index;
  }
  config->context_count = context_count;

  bud_config_set_defaults(config);

  *err = bud_ok();
  return config;

failed_get_index:
  free(config);

failed_get_object:
  json_value_free(json);

end:
  return NULL;
}
Пример #4
0
void bud_config_print_default() {
  bud_config_t config;

  memset(&config, 0, sizeof(config));

  /* Set zero-y values */
  config.worker_count = -1;
  config.log.stdio = -1;
  config.log.syslog = -1;
  config.frontend.keepalive = -1;
  config.frontend.ssl3 = -1;
  config.backend.keepalive = -1;
  config.restart_timeout = -1;

  bud_config_set_defaults(&config);

  fprintf(stdout, "{\n");
  fprintf(stdout, "  \"daemon\": false,\n");
  fprintf(stdout, "  \"workers\": %d,\n", config.worker_count);
  fprintf(stdout, "  \"restart_timeout\": %d,\n", config.restart_timeout);
  fprintf(stdout, "  \"log\": {\n");
  fprintf(stdout, "    \"level\": \"%s\",\n", config.log.level);
  fprintf(stdout, "    \"facility\": \"%s\",\n", config.log.facility);
  fprintf(stdout,
          "    \"stdio\": %s,\n",
          config.log.stdio ? "true" : "false");
  fprintf(stdout,
          "    \"syslog\": %s\n",
          config.log.syslog ? "true" : "false");
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"frontend\": {\n");
  fprintf(stdout, "    \"port\": %d,\n", config.frontend.port);
  fprintf(stdout, "    \"host\": \"%s\",\n", config.frontend.host);
  fprintf(stdout, "    \"keepalive\": %d,\n", config.frontend.keepalive);
  fprintf(stdout, "    \"proxyline\": false,\n");
  fprintf(stdout, "    \"security\": \"%s\",\n", config.frontend.security);
  fprintf(stdout, "    \"server_preference\": true,\n");
  if (config.frontend.ssl3)
    fprintf(stdout, "    \"ssl3\": true,\n");
  else
    fprintf(stdout, "    \"ssl3\": false,\n");
#ifdef OPENSSL_NPN_NEGOTIATED
  /* Sorry, hard-coded */
  fprintf(stdout, "    \"npn\": [\"http/1.1\", \"http/1.0\"],\n");
#endif  /* OPENSSL_NPN_NEGOTIATED */
  if (config.frontend.ciphers != NULL)
    fprintf(stdout, "    \"ciphers\": \"%s\",\n", config.frontend.ciphers);
  else
    fprintf(stdout, "    \"ciphers\": null,\n");
  fprintf(stdout, "    \"cert\": \"%s\",\n", config.frontend.cert_file);
  fprintf(stdout, "    \"key\": \"%s\",\n", config.frontend.key_file);
  fprintf(stdout, "    \"reneg_window\": %d,\n", config.frontend.reneg_window);
  fprintf(stdout, "    \"reneg_limit\": %d\n", config.frontend.reneg_limit);
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"backend\": {\n");
  fprintf(stdout, "    \"port\": %d,\n", config.backend.port);
  fprintf(stdout, "    \"host\": \"%s\",\n", config.backend.host);
  fprintf(stdout, "    \"keepalive\": %d\n", config.backend.keepalive);
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"sni\": {\n");
  fprintf(stdout, "    \"enabled\": false,\n");
  fprintf(stdout, "    \"port\": %d,\n", config.sni.port);
  fprintf(stdout, "    \"host\": \"%s\",\n", config.sni.host);
  fprintf(stdout, "    \"query\": \"%s\"\n", config.sni.query_fmt);
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"stapling\": {\n");
  fprintf(stdout, "    \"enabled\": false,\n");
  fprintf(stdout, "    \"port\": %d,\n", config.stapling.port);
  fprintf(stdout, "    \"host\": \"%s\",\n", config.stapling.host);
  fprintf(stdout, "    \"query\": \"%s\"\n", config.stapling.query_fmt);
  fprintf(stdout, "  },\n");
  fprintf(stdout, "  \"contexts\": []\n");
  fprintf(stdout, "}\n");
}
Пример #5
0
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;
}