uint8_t
*packet_process()
{
	uint8_t ret;
	uint8_t message[MESSAGE_SIZE];

	/* simple surface check of incoming data */
	ret = packet_sanity_check(packet_in, NETWORK_PACKET_SIZE);
	if (ret != OK)	{
		make_response(NACK, packet_out);
		uart_write("Packet failed sanity test\n");
		return packet_out;
	}

	/* verify hmac and decrypt data */
	ret = verify_and_decrypt_client_message(packet_in, message);
	if (ret == HMAC_FAILURE)	{
		make_response(HMAC_FAILURE, packet_out);
		uart_write("Packet has invalid hmac\n");
		return packet_out;
	}
	else if (ret == DEC_FAILURE)	{
		make_response(DEC_FAILURE, packet_out);
		uart_write("Packet encryption failed\n");
		return packet_out;
	}

	/* parse received, decrypted command */
	ret = parse_command(message);
	make_response(ret, packet_out);
	return packet_out;
}
 void get_diff(common::mprpc::rpc_result_object& result) const {
   result.response.push_back(make_response("1"));
   result.response.push_back(make_response("2"));
   result.response.push_back(make_response("3"));
   result.response.push_back(make_response("4"));
   result.error.push_back(common::mprpc::rpc_error("1", 1));
   result.error.push_back(common::mprpc::rpc_error("2", 2));
   result.error.push_back(common::mprpc::rpc_error("3", 3));
   result.error.push_back(common::mprpc::rpc_error("4", 4));
 }
Exemple #3
0
/* since /root <timestamp> [patterns] */
static void cmd_since(struct watchman_client* client, const json_ref& args) {
  const char *clockspec;

  /* resolve the root */
  if (json_array_size(args) < 3) {
    send_error_response(client, "not enough arguments for 'since'");
    return;
  }

  auto root = resolve_root_or_err(client, args, 1, false);
  if (!root) {
    return;
  }

  auto clock_ele = json_array_get(args, 2);
  clockspec = json_string_value(clock_ele);
  if (!clockspec) {
    send_error_response(client,
        "expected argument 2 to be a valid clockspec");
    return;
  }

  auto query = w_query_parse_legacy(root, args, 3, nullptr, clockspec, nullptr);

  auto res = w_query_execute(query.get(), root, nullptr);
  auto response = make_response();
  response.set({{"is_fresh_instance", json_boolean(res.is_fresh_instance)},
                {"clock", res.clockAtStartOfQuery.toJson()},
                {"files", std::move(res.resultsArray)}});

  add_root_warnings_to_response(response, root);
  send_and_dispose_response(client, std::move(response));
}
Exemple #4
0
static void cmd_debug_show_cursors(struct watchman_client *client, json_t *args)
{
    w_root_t *root;
    json_t *resp, *cursors;
    w_ht_iter_t i;

    /* resolve the root */
    if (json_array_size(args) != 2) {
        send_error_response(client,
                            "wrong number of arguments for 'debug-show-cursors'");
        return;
    }

    root = resolve_root_or_err(client, args, 1, false);

    if (!root) {
        return;
    }

    resp = make_response();

    w_root_lock(root);
    cursors = json_object_of_size(w_ht_size(root->cursors));
    if (w_ht_first(root->cursors, &i)) do {
            w_string_t *name = w_ht_val_ptr(i.key);
            set_prop(cursors, name->buf, json_integer(i.value));
        } while (w_ht_next(root->cursors, &i));
    w_root_unlock(root);

    set_prop(resp, "cursors", cursors);
    send_and_dispose_response(client, resp);
    w_root_delref(root);
}
Exemple #5
0
/* unsubscribe /root subname
 * Cancels a subscription */
static void cmd_unsubscribe(
    struct watchman_client* clientbase,
    const json_ref& args) {
  const char *name;
  bool deleted{false};
  struct watchman_user_client *client =
      (struct watchman_user_client *)clientbase;

  auto root = resolve_root_or_err(client, args, 1, false);
  if (!root) {
    return;
  }

  auto jstr = json_array_get(args, 2);
  name = json_string_value(jstr);
  if (!name) {
    send_error_response(
        client, "expected 2nd parameter to be subscription name");
    return;
  }

  auto sname = json_to_w_string(jstr);
  deleted = client->unsubByName(sname);

  auto resp = make_response();
  resp.set({{"unsubscribe", typed_string_to_json(name)},
            {"deleted", json_boolean(deleted)}});

  send_and_dispose_response(client, std::move(resp));
}
Exemple #6
0
/* debug-ageout */
static void cmd_debug_ageout(
    struct watchman_client* client,
    const json_ref& args) {

  /* resolve the root */
  if (json_array_size(args) != 3) {
    send_error_response(client,
                        "wrong number of arguments for 'debug-ageout'");
    return;
  }

  auto root = resolve_root_or_err(client, args, 1, false);
  if (!root) {
    return;
  }

  std::chrono::seconds min_age(json_integer_value(json_array_get(args, 2)));

  auto resp = make_response();

  root->performAgeOut(min_age);

  resp.set("ageout", json_true());
  send_and_dispose_response(client, std::move(resp));
}
Exemple #7
0
void send_error_response(struct watchman_client *client,
    const char *fmt, ...)
{
  char buf[WATCHMAN_NAME_MAX];
  va_list ap;
  json_t *resp = make_response();
  json_t *errstr;

  va_start(ap, fmt);
  vsnprintf(buf, sizeof(buf), fmt, ap);
  va_end(ap);

  errstr = typed_string_to_json(buf, W_STRING_MIXED);
  set_prop(resp, "error", errstr);

  json_incref(errstr);
  w_perf_add_meta(&client->perf_sample, "error", errstr);

  if (client->current_command) {
    char *command = NULL;
    command = json_dumps(client->current_command, 0);
    w_log(W_LOG_ERR, "send_error_response: %s failed: %s\n",
        command, buf);
    free(command);
  } else {
    w_log(W_LOG_ERR, "send_error_response: %s\n", buf);
  }

  send_and_dispose_response(client, resp);
}
Exemple #8
0
static void cmd_debug_show_cursors(
    struct watchman_client* client,
    const json_ref& args) {
  json_ref cursors;

  /* resolve the root */
  if (json_array_size(args) != 2) {
    send_error_response(client,
                        "wrong number of arguments for 'debug-show-cursors'");
    return;
  }

  auto root = resolve_root_or_err(client, args, 1, false);
  if (!root) {
    return;
  }

  auto resp = make_response();

  {
    auto map = root->inner.cursors.rlock();
    cursors = json_object_of_size(map->size());
    for (const auto& it : *map) {
      const auto& name = it.first;
      const auto& ticks = it.second;
      cursors.set(name.c_str(), json_integer(ticks));
    }
  }

  resp.set("cursors", std::move(cursors));
  send_and_dispose_response(client, std::move(resp));
}
Exemple #9
0
/* debug-ageout */
static void cmd_debug_ageout(struct watchman_client *client, json_t *args)
{
    w_root_t *root;
    json_t *resp;
    int min_age;

    /* resolve the root */
    if (json_array_size(args) != 3) {
        send_error_response(client,
                            "wrong number of arguments for 'debug-ageout'");
        return;
    }

    root = resolve_root_or_err(client, args, 1, false);

    if (!root) {
        return;
    }

    min_age = json_integer_value(json_array_get(args, 2));

    resp = make_response();

    w_root_lock(root);
    w_root_perform_age_out(root, min_age);
    w_root_unlock(root);

    set_prop(resp, "ageout", json_true());
    send_and_dispose_response(client, resp);
    w_root_delref(root);
}
Exemple #10
0
void w_log_to_clients(int level, const char *buf)
{
  json_t *json = NULL;
  w_ht_iter_t iter;

  if (!clients) {
    return;
  }

  pthread_mutex_lock(&w_client_lock);
  if (w_ht_first(clients, &iter)) do {
    struct watchman_client *client = w_ht_val_ptr(iter.value);

    if (client->log_level != W_LOG_OFF && client->log_level >= level) {
      json = make_response();
      if (json) {
        set_prop(json, "log", json_string_nocheck(buf));
        if (!enqueue_response(client, json, true)) {
          json_decref(json);
        }
      }
    }

  } while (w_ht_next(clients, &iter));
  pthread_mutex_unlock(&w_client_lock);
}
Exemple #11
0
/* get-sockname */
static void cmd_get_sockname(struct watchman_client* client, const json_ref&) {
  auto resp = make_response();

  resp.set("sockname", typed_string_to_json(get_sock_name(), W_STRING_BYTE));

  send_and_dispose_response(client, std::move(resp));
}
Exemple #12
0
/* find /root [patterns] */
static void cmd_find(struct watchman_client* client, const json_ref& args) {

  /* resolve the root */
  if (json_array_size(args) < 2) {
    send_error_response(client, "not enough arguments for 'find'");
    return;
  }

  auto root = resolve_root_or_err(client, args, 1, false);
  if (!root) {
    return;
  }

  auto query = w_query_parse_legacy(root, args, 2, nullptr, nullptr, nullptr);
  if (client->client_mode) {
    query->sync_timeout = std::chrono::milliseconds(0);
  }

  auto res = w_query_execute(query.get(), root, nullptr);
  auto response = make_response();
  response.set({{"clock", res.clockAtStartOfQuery.toJson()},
                {"files", std::move(res.resultsArray)}});

  send_and_dispose_response(client, std::move(response));
}
Exemple #13
0
/* watch /root */
static void cmd_watch(struct watchman_client *client, json_t *args)
{
  w_root_t *root;
  json_t *resp;

  /* resolve the root */
  if (json_array_size(args) != 2) {
    send_error_response(client, "wrong number of arguments to 'watch'");
    return;
  }

  root = resolve_root_or_err(client, args, 1, true);
  if (!root) {
    return;
  }

  resp = make_response();

  w_root_lock(root);
  if (root->failure_reason) {
    set_prop(resp, "error", json_string_nocheck(root->failure_reason->buf));
  } else if (root->cancelled) {
    set_prop(resp, "error", json_string_nocheck("root was cancelled"));
  } else {
    set_prop(resp, "watch", json_string_nocheck(root->root_path->buf));
  }
  send_and_dispose_response(client, resp);
  w_root_unlock(root);
  w_root_delref(root);
}
Exemple #14
0
static void cmd_debug_recrawl(struct watchman_client *client, json_t *args)
{
    w_root_t *root;
    json_t *resp;

    /* resolve the root */
    if (json_array_size(args) != 2) {
        send_error_response(client,
                            "wrong number of arguments for 'debug-recrawl'");
        return;
    }

    root = resolve_root_or_err(client, args, 1, false);

    if (!root) {
        return;
    }

    resp = make_response();

    w_root_lock(root);
    w_root_schedule_recrawl(root, "debug-recrawl");
    w_root_unlock(root);

    set_prop(resp, "recrawl", json_true());
    send_and_dispose_response(client, resp);
    w_root_delref(root);
}
Exemple #15
0
/* find /root [patterns] */
static void cmd_find(struct watchman_client *client, json_t *args)
{
    w_root_t *root;
    w_query *query;
    char *errmsg = NULL;
    struct w_query_field_list field_list;
    w_query_res res;
    json_t *response;
    json_t *file_list;
    char clockbuf[128];

    /* resolve the root */
    if (json_array_size(args) < 2) {
        send_error_response(client, "not enough arguments for 'find'");
        return;
    }

    root = resolve_root_or_err(client, args, 1, false);
    if (!root) {
        return;
    }

    query = w_query_parse_legacy(root, args, &errmsg, 2, NULL, NULL, NULL);
    if (errmsg) {
        send_error_response(client, "%s", errmsg);
        free(errmsg);
        w_root_delref(root);
        return;
    }

    w_query_legacy_field_list(&field_list);

    if (client->client_mode) {
        query->sync_timeout = 0;
    }

    if (!w_query_execute(query, root, &res, NULL, NULL)) {
        send_error_response(client, "query failed: %s", res.errmsg);
        w_query_result_free(&res);
        w_root_delref(root);
        w_query_delref(query);
        return;
    }

    w_query_delref(query);

    file_list = w_query_results_to_json(&field_list,
                                        res.num_results, res.results);
    w_query_result_free(&res);

    response = make_response();
    if (clock_id_string(res.root_number, res.ticks, clockbuf, sizeof(clockbuf))) {
        set_prop(response, "clock", json_string_nocheck(clockbuf));
    }
    set_prop(response, "files", file_list);

    send_and_dispose_response(client, response);
    w_root_delref(root);
}
Exemple #16
0
void respond(request **req, int client_socket) {
	response *resp = make_response(*req);
	response_write(resp, client_socket);
	response_clear(resp);

	request_clear(*req);
	*req = request_new();
}
Exemple #17
0
/* list-capabilities */
static void cmd_list_capabilities(
    struct watchman_client* client,
    const json_ref&) {
  auto resp = make_response();

  resp.set("capabilities", w_capability_get_list());
  send_and_dispose_response(client, std::move(resp));
}
Exemple #18
0
static void cmd_debug_drop_privs(
    struct watchman_client* client,
    const json_ref&) {
  client->client_is_owner = false;

  auto resp = make_response();
  resp.set("owner", json_boolean(client->client_is_owner));
  send_and_dispose_response(client, std::move(resp));
}
Exemple #19
0
////////////////////////////////////////////////////////// send_message() //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//int send_message(char*, char*, char*, char* ) 是短信发送接口函数,只要将手机号,密码,对方手机号和短信内容作为参数传过来,就可以发送短信了。
//  
void send_message(char* fromPhone, char* password, char* toPhone, char* dataSend)
{
	static char *systemconfig_xml = NULL, *URL= NULL, *sipc_proxy = NULL, *SSIAppSignIn_xml = NULL, *domain, *fetion_num, *fetion_sip, *ssiapp_signin ,  *nonce, *cnonce;           
	static char data[400], *login_xml_1=NULL, *login_xml_2=NULL, *login_request_1=NULL, *login_request_2=NULL, *login_1=NULL, *login_2=NULL, *server_response=NULL; 
	char* response;	
	//static char myname[200];	
	char *re_back;
	static char *data_send;
	char *ip="221.176.31.33";
	char *port="8080";
		
	domain = "fetion.com.cn";
	//判断是否为空
	if (fromPhone == NULL || password == NULL) 
		return;
    /////////////// initalize ///////////////////////////////////////////////
	SSIAppSignIn_xml = SSIAppSignIn(fromPhone, password);  //通过curl发送https请求,验证身份,并从网页获取相关信息
	fetion_num = get_value(SSIAppSignIn_xml , "sip:", "@");   //从返回的xml中获取飞信号 fetion_num="64738765"
	fetion_sip = get_value(SSIAppSignIn_xml, "uri=\"", "\"");   //从返回的xml中获取sip fetion_sip="sip:[email protected];p=xxxx" uri="sip:[email protected];p=6176" type="3" 
 
    ////////////////// login ////////////////////////////////////// /////////////////////////////////////////
	//登陆服务器,这是个标准的Digest Authentication验证过程
	//
	login_xml_1 = "<args><device type=\"PC\" version=\"36\" client-version=\"3.3.0370\" /><caps value=\"simple-im;im-session;temp-group;personal-group\" /><events value=\"contact;permission;system-message;personal-group\" /><user-info attributes=\"all\" /><presence><basic value=\"400\" desc=\"\" /></presence></args>";
    sprintf(data,"R %s SIP-C/2.0\r\nF: %s\r\nI: 1\r\nQ: 1 R\r\nL: %d\r\n\r\n", domain, fetion_num, strlen(login_xml_1));
	data_send = strcating(data, login_xml_1);
	socket_init(ip,port);
	server_response = request(data_send);  //通过sipc的request()函数和服务器进行sip交互过程

  
	//
    ////nonce:
	//
	nonce = get_value(server_response, "nonce=\"", "\"");

	login_xml_2 = "<args><device type=\"PC\" version=\"36\" client-version=\"3.3.0370\" /><caps value=\"simple-im;im-session;temp-group;personal-group\" /><events value=\"contact;permission;system-message;personal-group\" /><user-info attributes=\"all\" /><presence><basic value=\"400\" desc=\"\" /></presence></args>";  
	// 
	////cnonce:
	//
	cnonce = get_cnonce();
	//
	////response:
	//
	response = make_response(fetion_num, password, domain, nonce, cnonce );

    //getchar();
	sprintf(data,"R %s SIP-C/2.0\r\nF: %s\r\nI: 1\r\nQ: 2 R\r\nA: Digest response=\"%s\",cnonce=\"%s\"\r\nL: %d\r\n\r\n", domain, fetion_num, response, cnonce, strlen(login_xml_2));
	data_send = strcating(data, login_xml_2);	
	server_response = request(data_send);//通过sipc的request()函数和服务器进行sip交互过程
	re_back = get_value(server_response, "SIP-C/2.0 ","F");
	//////////////////////////////////////////////////////////////
	//sendSMS_toMyself( )发送短信
	//
	sendSMS_toMyself( domain, fetion_num, fetion_sip, dataSend );
	//sendSMS_toOther( domain, fetion_num, toPhone, dataSend );
    sip_logout(domain, fetion_num);
 }  
Exemple #20
0
/* get-pid */
void cmd_get_pid(struct watchman_client *client, json_t *args)
{
  json_t *resp = make_response();

  unused_parameter(args);

  set_prop(resp, "pid", json_integer(getpid()));

  send_and_dispose_response(client, resp);
}
Exemple #21
0
/* get-sockname */
void cmd_get_sockname(struct watchman_client *client, json_t *args)
{
  json_t *resp = make_response();

  unused_parameter(args);

  set_prop(resp, "sockname", json_string(get_sock_name()));

  send_and_dispose_response(client, resp);
}
Exemple #22
0
static void cmd_shutdown(struct watchman_client *client, json_t *args) {
  json_t *resp = make_response();
  unused_parameter(args);

  w_log(W_LOG_ERR, "shutdown-server was requested, exiting!\n");
  w_request_shutdown();

  set_prop(resp, "shutdown-server", json_true());
  send_and_dispose_response(client, resp);
}
void
RestEngineUri::handle_delete(http_request request)
{
    std::cout << request.method() << " : " << request.absolute_uri().path() << std::endl;
    http_response response(status_codes::OK);
    std::string resultstr("Not Supported");
    std::pair<bool, std::string> result {true, std::string()};
    make_response(response, resultstr, result);
    request.reply(response);
}
Exemple #24
0
/* trigger /root triggername [watch patterns] -- cmd to run
 * Sets up a trigger so that we can execute a command when a change
 * is detected */
void cmd_trigger(struct watchman_client *client, json_t *args)
{
  w_root_t *root;
  struct watchman_trigger_command *cmd;
  json_t *resp;
  json_t *trig;
  char *errmsg = NULL;

  root = resolve_root_or_err(client, args, 1, true);
  if (!root) {
    return;
  }

  if (json_array_size(args) < 3) {
    send_error_response(client, "not enough arguments");
    goto done;
  }

  trig = json_array_get(args, 2);
  if (json_is_string(trig)) {
    trig = build_legacy_trigger(client, args);
    if (!trig) {
      goto done;
    }
  } else {
    // Add a ref so that we don't need to conditionally decref later
    // for the legacy case later
    json_incref(trig);
  }

  cmd = w_build_trigger_from_def(root, trig, &errmsg);
  json_decref(trig);

  if (!cmd) {
    send_error_response(client, "%s", errmsg);
    goto done;
  }

  w_root_lock(root);
  w_ht_replace(root->commands, w_ht_ptr_val(cmd->triggername),
      w_ht_ptr_val(cmd));
  w_root_unlock(root);

  w_state_save();

  resp = make_response();
  set_prop(resp, "triggerid", json_string_nocheck(cmd->triggername->buf));
  send_and_dispose_response(client, resp);

done:
  if (errmsg) {
    free(errmsg);
  }
  w_root_delref(root);
}
Exemple #25
0
/* watch-list
 * Returns a list of watched roots */
static void cmd_watch_list(struct watchman_client *client, json_t *args)
{
  json_t *resp;
  json_t *root_paths;
  unused_parameter(args);

  resp = make_response();
  root_paths = w_root_watch_list_to_json();
  set_prop(resp, "roots", root_paths);
  send_and_dispose_response(client, resp);
}
Exemple #26
0
/* version */
void cmd_version(struct watchman_client *client, json_t *args)
{
  json_t *resp = make_response();

  unused_parameter(args);

#ifdef WATCHMAN_BUILD_INFO
  set_prop(resp, "buildinfo", json_string(WATCHMAN_BUILD_INFO));
#endif

  send_and_dispose_response(client, resp);
}
Exemple #27
0
static void cmd_debug_get_subscriptions(
    struct watchman_client* clientbase,
    const json_ref& args) {
  auto client = (watchman_user_client*)clientbase;

  auto root = resolve_root_or_err(client, args, 1, false);

  auto resp = make_response();
  auto debug_info = root->unilateralResponses->getDebugInfo();
  // copy over all the key-value pairs from debug_info
  resp.object().insert(debug_info.object().begin(), debug_info.object().end());
  send_and_dispose_response(clientbase, std::move(resp));
}
void
RestRollupsUri::handle_get(http_request request)
{
    std::cout << request.method() << " : " << request.absolute_uri().path() << std::endl;
    http_response response(status_codes::OK);
    std::string resultstr("Not Supported");
    std::pair<bool, std::string> result {true, std::string()};

    resultstr = m_s.show_rollup_structure();

    make_response(response, resultstr, result);
    request.reply(response);
    return;
}
void
RestRollupsUri::handle_post(http_request request)
{
    std::cout << request.method() << " : " << request.absolute_uri().path() << std::endl;
    int rc = 0;
    std::string resultstr;
    std::pair<bool, std::string> result {true, std::string()};

    char json[1024];

    // extract json from request
    snprintf(json, sizeof(json), "%s", request.extract_string(true).get().c_str());
    std::cout << "JSON:\n" << json << std::endl;

    rapidjson::Document document; 
    if (document.Parse(json).HasParseError())
    {
        rc = 1;
        resultstr += "document invalid";
    }

    rapidjson::SchemaValidator validator(*_schema);
    if (!document.Accept(validator)) {
        rc = 1;
        resultstr += get_schema_validation_error(&validator);
    }

    rapidjson::Value::MemberIterator name = document.FindMember("name");
    rapidjson::Value::MemberIterator nocsv = document.FindMember("nocsv");
    rapidjson::Value::MemberIterator quantity = document.FindMember("quantity");
    rapidjson::Value::MemberIterator maxdroop = document.FindMember("maxDroop");
    rapidjson::Value::MemberIterator maxsdroop_validation = document.FindMember("maxDroopMaxtoMinIOPSSection");

    // Execute Ivy Engine command
    if (rc == 0)
    {
        std::unique_lock<std::mutex> u_lk(goStatementMutex);
        std::pair<int, std::string> 
        rslt = m_s.create_rollup(name->value.GetString(),
                   (nocsv != document.MemberEnd() ? nocsv->value.GetBool() : false),
                   false /* have_quantity_validation */,
                   (maxsdroop_validation != document.MemberEnd() ? maxsdroop_validation->value.GetBool() : false),
                   (quantity != document.MemberEnd() ? quantity->value.GetInt() : 1),
                   (maxdroop != document.MemberEnd() ? maxdroop->value.GetDouble() : 6.95323e-310));
    }

    http_response response(status_codes::OK);
    make_response(response, resultstr, result);
    request.reply(response);
}
Exemple #30
0
static json_t *build_subscription_results(
    struct watchman_client_subscription *sub,
    w_root_t *root)
{
  w_query_res res;
  json_t *response;
  json_t *file_list;
  char clockbuf[128];

  w_log(W_LOG_DBG, "running subscription rules! since %" PRIu32 "\n",
      sub->since.ticks);

  // Subscriptions never need to sync explicitly; we are only dispatched
  // at settle points which are by definition sync'd to the present time
  sub->query->sync_timeout = 0;
  if (!w_query_execute(sub->query, root, &res, subscription_generator, sub)) {
    w_log(W_LOG_ERR, "error running subscription query: %s", res.errmsg);
    w_query_result_free(&res);
    return NULL;
  }

  w_log(W_LOG_DBG, "subscription generated %" PRIu32 " results\n",
      res.num_results);

  file_list = w_query_results_to_json(&sub->field_list,
      res.num_results, res.results);
  w_query_result_free(&res);

  if (res.num_results == 0) {
    return NULL;
  }

  response = make_response();

  if (clock_id_string(sub->since.ticks, clockbuf, sizeof(clockbuf))) {
    set_prop(response, "since", json_string_nocheck(clockbuf));
  }
  if (clock_id_string(res.ticks, clockbuf, sizeof(clockbuf))) {
    set_prop(response, "clock", json_string_nocheck(clockbuf));
  }
  sub->since.is_timestamp = false;
  sub->since.ticks = res.ticks;

  set_prop(response, "files", file_list);
  set_prop(response, "root", json_string(root->root_path->buf));
  set_prop(response, "subscription", json_string(sub->name->buf));

  return response;
}