// Translate from the legacy array into the new style, then // delegate to the main parser. // We build a big anyof expression w_query *w_query_parse_legacy(json_t *args, char **errmsg, int start, uint32_t *next_arg, const char *clockspec) { bool include = true; bool negated = false; uint32_t i; const char *term_name = "match"; json_t *query_array; json_t *included = NULL, *excluded = NULL; json_t *term; json_t *container; json_t *query_obj = json_object(); w_query *query; if (!json_is_array(args)) { *errmsg = strdup("Expected an array"); return NULL; } for (i = start; i < json_array_size(args); i++) { const char *arg = json_string_value(json_array_get(args, i)); if (!arg) { /* not a string value! */ ignore_result(asprintf(errmsg, "rule @ position %d is not a string value", i)); return NULL; } } for (i = start; i < json_array_size(args); i++) { const char *arg = json_string_value(json_array_get(args, i)); if (!strcmp(arg, "--")) { i++; break; } if (!strcmp(arg, "-X")) { include = false; continue; } if (!strcmp(arg, "-I")) { include = true; continue; } if (!strcmp(arg, "!")) { negated = true; continue; } if (!strcmp(arg, "-P")) { term_name = "ipcre"; continue; } if (!strcmp(arg, "-p")) { term_name = "pcre"; continue; } // Which group are we going to file it into if (include) { if (!included) { included = json_pack("[s]", "anyof"); } container = included; } else { if (!excluded) { excluded = json_pack("[s]", "anyof"); } container = excluded; } term = json_pack("[sss]", term_name, arg, "wholename"); if (negated) { term = json_pack("[so]", "not", term); } json_array_append_new(container, term); // Reset negated flag negated = false; term_name = "match"; } if (excluded) { term = json_pack("[so]", "not", excluded); excluded = term; } if (included && excluded) { query_array = json_pack("[soo]", "allof", excluded, included); } else if (included) { query_array = included; } else { query_array = excluded; } // query_array may be NULL, which means find me all files. // Otherwise, it is the expression we want to use. if (query_array) { json_object_set_new_nocheck(query_obj, "expression", query_array); } // For trigger if (next_arg) { *next_arg = i; } if (clockspec) { json_object_set_new_nocheck(query_obj, "since", json_string_nocheck(clockspec)); } /* compose the query with the field list */ query = w_query_parse(query_obj, errmsg); json_decref(query_obj); return query; }
/* Call the simple functions not covered by other tests of the public API */ int main() { json_t *value; value = json_integer(1); if(json_typeof(value) != JSON_INTEGER) fail("json_typeof failed"); if(json_is_object(value)) fail("json_is_object failed"); if(json_is_array(value)) fail("json_is_array failed"); if(json_is_string(value)) fail("json_is_string failed"); if(!json_is_integer(value)) fail("json_is_integer failed"); if(json_is_real(value)) fail("json_is_real failed"); if(!json_is_number(value)) fail("json_is_number failed"); if(json_is_true(value)) fail("json_is_true failed"); if(json_is_false(value)) fail("json_is_false failed"); if(json_is_boolean(value)) fail("json_is_boolean failed"); if(json_is_null(value)) fail("json_is_null failed"); json_decref(value); value = json_string("foo"); if(!value) fail("json_string failed"); if(strcmp(json_string_value(value), "foo")) fail("invalid string value"); if(json_string_set(value, "bar")) fail("json_string_set failed"); if(strcmp(json_string_value(value), "bar")) fail("invalid string value"); json_decref(value); value = json_string(NULL); if(value) fail("json_string(NULL) failed"); /* invalid UTF-8 */ value = json_string("a\xefz"); if(value) fail("json_string(<invalid utf-8>) failed"); value = json_string_nocheck("foo"); if(!value) fail("json_string_nocheck failed"); if(strcmp(json_string_value(value), "foo")) fail("invalid string value"); if(json_string_set_nocheck(value, "bar")) fail("json_string_set_nocheck failed"); if(strcmp(json_string_value(value), "bar")) fail("invalid string value"); json_decref(value); /* invalid UTF-8 */ value = json_string_nocheck("qu\xff"); if(!value) fail("json_string_nocheck failed"); if(strcmp(json_string_value(value), "qu\xff")) fail("invalid string value"); if(json_string_set_nocheck(value, "\xfd\xfe\xff")) fail("json_string_set_nocheck failed"); if(strcmp(json_string_value(value), "\xfd\xfe\xff")) fail("invalid string value"); json_decref(value); value = json_integer(123); if(!value) fail("json_integer failed"); if(json_integer_value(value) != 123) fail("invalid integer value"); if(json_number_value(value) != 123.0) fail("invalid number value"); if(json_integer_set(value, 321)) fail("json_integer_set failed"); if(json_integer_value(value) != 321) fail("invalid integer value"); if(json_number_value(value) != 321.0) fail("invalid number value"); json_decref(value); value = json_real(123.123); if(!value) fail("json_real failed"); if(json_real_value(value) != 123.123) fail("invalid integer value"); if(json_number_value(value) != 123.123) fail("invalid number value"); if(json_real_set(value, 321.321)) fail("json_real_set failed"); if(json_real_value(value) != 321.321) fail("invalid real value"); if(json_number_value(value) != 321.321) fail("invalid number value"); json_decref(value); value = json_true(); if(!value) fail("json_true failed"); json_decref(value); value = json_false(); if(!value) fail("json_false failed"); json_decref(value); value = json_null(); if(!value) fail("json_null failed"); json_decref(value); /* Test reference counting on singletons (true, false, null) */ value = json_true(); if(value->refcount != (size_t)-1) fail("refcounting true works incorrectly"); json_decref(value); if(value->refcount != (size_t)-1) fail("refcounting true works incorrectly"); json_incref(value); if(value->refcount != (size_t)-1) fail("refcounting true works incorrectly"); value = json_false(); if(value->refcount != (size_t)-1) fail("refcounting false works incorrectly"); json_decref(value); if(value->refcount != (size_t)-1) fail("refcounting false works incorrectly"); json_incref(value); if(value->refcount != (size_t)-1) fail("refcounting false works incorrectly"); value = json_null(); if(value->refcount != (size_t)-1) fail("refcounting null works incorrectly"); json_decref(value); if(value->refcount != (size_t)-1) fail("refcounting null works incorrectly"); json_incref(value); if(value->refcount != (size_t)-1) fail("refcounting null works incorrectly"); return 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]; struct w_clockspec *since_spec = sub->query->since_spec; if (since_spec && since_spec->tag == w_cs_clock) { w_log(W_LOG_DBG, "running subscription rules! since %" PRIu32 "\n", since_spec->clock.ticks); } else { w_log(W_LOG_DBG, "running subscription rules!\n"); } // 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); if (res.num_results == 0) { w_query_result_free(&res); return NULL; } file_list = w_query_results_to_json(&sub->field_list, res.num_results, res.results); w_query_result_free(&res); response = make_response(); // It is way too much of a hassle to try to recreate the clock value if it's // not a relative clock spec, and it's only going to happen on the first run // anyway, so just skip doing that entirely. if (since_spec && since_spec->tag == w_cs_clock && clock_id_string(since_spec->clock.root_number, since_spec->clock.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "since", json_string_nocheck(clockbuf)); } if (clock_id_string(res.root_number, res.ticks, clockbuf, sizeof(clockbuf))) { set_prop(response, "clock", json_string_nocheck(clockbuf)); } // create a new spec that will be used the next time if (since_spec) { w_clockspec_free(since_spec); since_spec = NULL; } sub->query->since_spec = w_clockspec_new_clock(res.root_number, res.ticks); set_prop(response, "is_fresh_instance", json_boolean(res.is_fresh_instance)); 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; }
json_t *broker_handshake_handle_conn(Broker *broker, const char *dsId, const char *token, json_t *handshake) { if (dslink_map_contains(&broker->client_connecting, (void *) dsId)) { ref_t *ref = dslink_map_remove_get(&broker->client_connecting, (void *) dsId); RemoteDSLink *link = ref->data; dslink_map_remove(&broker->client_connecting, (void *) link->name); broker_remote_dslink_free(link); dslink_free(link); dslink_decref(ref); } RemoteDSLink *link = dslink_calloc(1, sizeof(RemoteDSLink)); json_t *resp = json_object(); if (!(link && resp)) { goto fail; } if (broker_remote_dslink_init(link) != 0) { goto fail; } link->broker = broker; link->auth = dslink_calloc(1, sizeof(RemoteAuth)); if (!link->auth) { goto fail; } if (dslink_handshake_generate_key_pair(&link->auth->tempKey) != 0) { log_err("Failed to create temporary key for DSLink\n"); goto fail; } { json_t *jsonPubKey = json_object_get(handshake, "publicKey"); if (!jsonPubKey) { goto fail; } const char *tmp = json_string_value(jsonPubKey); if (!tmp) { goto fail; } tmp = dslink_strdup(tmp); if (!tmp) { goto fail; } link->auth->pubKey = tmp; } char tempKey[90]; size_t tempKeyLen = 0; if (dslink_handshake_encode_pub_key(&link->auth->tempKey, tempKey, sizeof(tempKey), &tempKeyLen) != 0) { goto fail; } if (generate_salt((unsigned char *) link->auth->salt, sizeof(link->auth->salt)) != 0) { goto fail; } json_object_set_new_nocheck(resp, "wsUri", json_string_nocheck("/ws")); json_object_set_new_nocheck(resp, "tempKey", json_string_nocheck(tempKey)); json_object_set_new_nocheck(resp, "salt", json_string_nocheck(link->auth->salt)); if (json_boolean_value(json_object_get(handshake, "isResponder"))) { link->isResponder = 1; } if (json_boolean_value(json_object_get(handshake, "isRequester"))) { link->isRequester = 1; } json_t *linkData = json_object_get(handshake, "linkData"); if (json_is_object(linkData)) { json_incref(linkData); link->linkData = linkData; } { char buf[512] = {0}; snprintf(buf, sizeof(buf), "/downstream/"); char *name = buf + sizeof("/downstream/")-1; size_t dsIdLen = strlen(dsId); if (dsIdLen < 44) { goto fail; } size_t nameLen = dsIdLen - 43; if (dsId[nameLen - 1] == '-') { nameLen--; } int nodeExists = 0; // find a valid name from broker->client_names memcpy(name, dsId, nameLen); while (1) { ref_t *ref = dslink_map_get(&broker->client_connecting, name); if (ref) { RemoteDSLink *l = ref->data; if (l && l->dsId && strcmp(l->dsId->data, dsId) == 0) { dslink_map_remove(&broker->client_connecting, name); broker_remote_dslink_free(l); break; } else { name[nameLen] = dsId[nameLen]; nameLen++; } } ref = dslink_map_get(broker->downstream->children, (void *) name); if (ref == NULL) { break; } if (!((DownstreamNode *) ref->data)->dsId || strcmp(dsId, ((DownstreamNode *) ref->data)->dsId->data) == 0) { nodeExists = 1; break; } name[nameLen] = dsId[nameLen]; nameLen++; } if (!nodeExists && broker_enable_token) { if (!token) { log_err("Failed to connet, need token\n"); goto fail; } BrokerNode* tokenNode = get_token_node(token, dsId); if (tokenNode) { DownstreamNode *node = broker_init_downstream_node(broker->downstream, name); if (json_is_true(json_object_get(node->meta, "$$managed"))) { json_object_set_new_nocheck(node->meta, "$$token", json_string_nocheck(tokenNode->name)); } node->dsId = dslink_str_ref(dsId); if (broker->downstream->list_stream) { update_list_child(broker->downstream, broker->downstream->list_stream, link->name); } json_t *group = json_object_get(tokenNode->meta, "$$group"); if (json_is_string(group)) { json_object_set_nocheck(node->meta, "$$group", group); } token_used(tokenNode); broker_downstream_nodes_changed(broker); } else { log_err("Invalid token: %s\n", token); goto fail; } } json_object_set_new_nocheck(resp, "path", json_string_nocheck(buf)); link->path = dslink_strdup(buf); if (!link->path) { goto fail; } link->name = link->path + sizeof("/downstream/") - 1; // add to connecting map with the name if (dslink_map_set(&broker->client_connecting, dslink_ref((void *) link->name, NULL), dslink_ref(link, NULL)) != 0) { dslink_free((void *) link->path); goto fail; } } { ref_t *tmp = dslink_ref(dslink_strdup(dsId), dslink_free); if (!tmp) { goto fail; } // add to connecting map with dsId if (dslink_map_set(&broker->client_connecting, tmp, dslink_ref(link, NULL)) != 0) { dslink_free(tmp); goto fail; } } return resp; fail: if (link) { broker_remote_dslink_free(link); dslink_free((void *) link->path); dslink_free(link); } DSLINK_CHECKED_EXEC(json_decref, resp); return NULL; }
/* 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) { struct watchman_rule *rules; w_root_t *root; uint32_t next_arg = 0; struct watchman_trigger_command *cmd; json_t *resp; const char *name; char buf[128]; root = resolve_root_or_err(client, args, 1, true); if (!root) { return; } if (json_array_size(args) < 2) { send_error_response(client, "not enough arguments"); goto done; } name = json_string_value(json_array_get(args, 2)); if (!name) { send_error_response(client, "expected 2nd parameter to be trigger name"); goto done; } if (!parse_watch_params(3, args, &rules, &next_arg, buf, sizeof(buf))) { send_error_response(client, "invalid rule spec: %s", buf); goto done; } if (next_arg >= json_array_size(args)) { send_error_response(client, "no command was specified"); goto done; } cmd = calloc(1, sizeof(*cmd)); if (!cmd) { send_error_response(client, "no memory!"); goto done; } cmd->rules = rules; cmd->argc = json_array_size(args) - next_arg; cmd->argv = w_argv_copy_from_json(args, next_arg); if (!cmd->argv) { free(cmd); send_error_response(client, "unable to build argv array"); goto done; } cmd->triggername = w_string_new(name); w_root_lock(root); w_ht_replace(root->commands, (w_ht_val_t)cmd->triggername, (w_ht_val_t)cmd); w_root_unlock(root); w_state_save(); resp = make_response(); set_prop(resp, "triggerid", json_string_nocheck(name)); send_and_dispose_response(client, resp); done: w_root_delref(root); }
int broker_handshake_handle_ws(Broker *broker, Client *client, const char *dsId, const char *auth, const char *wsAccept) { ref_t *oldDsId = NULL; ref_t *ref = dslink_map_remove_get(&broker->client_connecting, (char *) dsId); if (!ref) { return 1; } RemoteDSLink *link = ref->data; dslink_decref(ref); if (link->name) { dslink_map_remove(&broker->client_connecting, (char *) link->name); } if (!(auth && link->auth->pubKey)) { return 1; } uv_timer_t *ping_timer = NULL; int ret = 0; { // Perform auth check char expectedAuth[90]; if (dslink_handshake_gen_auth_key(&link->auth->tempKey, link->auth->pubKey, link->auth->salt, (unsigned char *) expectedAuth, sizeof(expectedAuth)) != 0) { ret = 1; goto exit; } if (strcmp(expectedAuth, auth) != 0) { ret = 1; goto exit; } } DownstreamNode *node = NULL; int pendingUpdateList = 0; { // Handle retrieval of the downstream node ref = dslink_map_get(broker->downstream->children, (char *) link->name); if (!ref) { node = broker_init_downstream_node(broker->downstream, link->name); if (!node) { ret = 1; goto exit; } oldDsId = dslink_ref(dslink_strdup(dsId), dslink_free); if (broker->downstream->list_stream) { pendingUpdateList = 1; } broker_downstream_nodes_changed(broker); } else { node = ref->data; oldDsId = node->dsId; } } if (node->link) { Client *c = node->link->client; broker_close_link(node->link); uv_poll_t *poll = c->poll; dslink_socket_free(c->sock); dslink_free(c); uv_close((uv_handle_t *) poll, broker_free_handle); } // add permission group to link json_t *group = json_object_get(node->meta, "$$group"); permission_groups_load(&link->permission_groups, dsId, json_string_value(group)); link->client = client; link->dsId = oldDsId; link->node = node; node->dsId = oldDsId; client->sock_data = link; json_object_set_new(node->meta, "$$dsId", json_string_nocheck(dsId)); wslay_event_context_ptr ws; if (wslay_event_context_server_init(&ws, broker_ws_callbacks(), link) != 0) { ret = 1; goto exit; } link->ws = ws; broker_ws_send_init(client->sock, wsAccept); ping_timer = dslink_malloc(sizeof(uv_timer_t)); ping_timer->data = link; uv_timer_init(link->client->poll->loop, ping_timer); uv_timer_start(ping_timer, dslink_handle_ping, 1000, 30000); link->pingTimerHandle = ping_timer; // set the ->link and update all existing stream broker_dslink_connect(node, link); if (pendingUpdateList) { update_list_child(broker->downstream, broker->downstream->list_stream, link->name); } log_info("DSLink `%s` has connected\n", dsId); exit: mbedtls_ecdh_free(&link->auth->tempKey); dslink_free((void *) link->auth->pubKey); dslink_free(link->auth); link->auth = NULL; if (ret != 0) { dslink_map_free(&link->requester_streams); dslink_map_free(&link->responder_streams); dslink_free((char *)link->path); dslink_free(link); if (ping_timer) { uv_timer_stop(ping_timer); uv_close((uv_handle_t *) ping_timer, broker_free_handle); } } return ret; }
FReturnCode NativeCommand::SearchCommand(intrusive_ptr< ConnectionInstance >& con, string& payload) { //DLOG(INFO) << "Starting search with payload " << payload; static string FKSstring("FKS"); static double timeout = 5.0; double time = Server::getEventTime(); if (con->timers[FKSstring] > (time - timeout)) return FERR_THROTTLE_SEARCH; else con->timers[FKSstring] = time; typedef unordered_set<ConnectionPtr> clist_t; clist_t tosearch; const conptrmap_t cons = ServerState::getConnections(); for (conptrmap_t::const_iterator i = cons.begin(); i != cons.end(); ++i) { if ((i->second != con) && (i->second->kinkList.size() != 0) && (i->second->status == "online" || i->second->status == "looking")) tosearch.insert(i->second); } json_t* rootnode = json_loads(payload.c_str(), 0, 0); if (!rootnode) return FERR_BAD_SYNTAX; json_t* kinksnode = json_object_get(rootnode, "kinks"); if (!json_is_array(kinksnode)) return FERR_BAD_SYNTAX; if (json_array_size(kinksnode) > 5) return FERR_TOO_MANY_SEARCH_TERMS; json_t* gendersnode = json_object_get(rootnode, "genders"); if (json_is_array(gendersnode)) SearchFilterList(gendersnode, tosearch, "Gender"); json_t* orientationsnode = json_object_get(rootnode, "orientations"); if (json_is_array(orientationsnode)) SearchFilterList(orientationsnode, tosearch, "Orientation"); json_t* languagesnode = json_object_get(rootnode, "languages"); if (json_is_array(languagesnode)) SearchFilterList(languagesnode, tosearch, "Language preference"); json_t* furryprefsnode = json_object_get(rootnode, "furryprefs"); if (json_is_array(furryprefsnode)) SearchFilterList(furryprefsnode, tosearch, "Furry preference"); json_t* rolesnode = json_object_get(rootnode, "roles"); if (json_is_array(rolesnode)) SearchFilterList(rolesnode, tosearch, "Dom/Sub Role"); json_t* positionsnode = json_object_get(rootnode, "positions"); if (json_is_array(positionsnode)) SearchFilterList(positionsnode, tosearch, "Position"); if (json_array_size(kinksnode) > 0) SearchFilterListF(kinksnode, tosearch); int num_found = tosearch.size(); if (num_found == 0) return FERR_NO_SEARCH_RESULTS; else if (num_found > 350) return FERR_TOO_MANY_SEARCH_RESULTS; json_t* newroot = json_object(); json_t* chararray = json_array(); for (clist_t::const_iterator i = tosearch.begin(); i != tosearch.end(); ++i) { json_array_append_new(chararray, json_string_nocheck((*i)->characterName.c_str()) ); } json_object_set_new_nocheck(newroot, "characters", chararray); json_object_set_new_nocheck(newroot, "kinks", kinksnode); string message("FKS "); const char* fksstr = json_dumps(newroot, JSON_COMPACT); message += fksstr; free((void*) fksstr); json_decref(newroot); MessagePtr outMessage(MessageBuffer::fromString(message)); con->send(outMessage); json_decref(rootnode); //DLOG(INFO) << "Finished search."; return FERR_OK; }
static json_t *json_string_copy(json_t *string) { return json_string_nocheck(json_string_value(string)); }
la_codec_value_t *la_codec_string_nocheck(const char *value) { return (la_codec_value_t *) json_string_nocheck(value); }
/* query /root {query} */ void cmd_query(struct watchman_client *client, json_t *args) { w_root_t *root; w_query *query; json_t *query_spec; char *errmsg = NULL; w_query_res res; json_t *response; json_t *file_list, *jfield_list; char clockbuf[128]; struct w_query_field_list field_list; if (json_array_size(args) != 3) { send_error_response(client, "wrong number of arguments for 'query'"); return; } root = resolve_root_or_err(client, args, 1, false); if (!root) { return; } query_spec = json_array_get(args, 2); jfield_list = json_object_get(query_spec, "fields"); if (!parse_field_list(jfield_list, &field_list, &errmsg)) { send_error_response(client, "invalid field list: %s", errmsg); free(errmsg); w_root_delref(root); return; } query = w_query_parse(query_spec, &errmsg); if (!query) { send_error_response(client, "failed to parse query: %s", errmsg); free(errmsg); w_root_delref(root); return; } 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.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); }