void broker_subscribe_remote(DownstreamNode *respNode, SubRequester *subreq, const char *respPath) { DownstreamNode *reqNode = subreq->reqNode; ref_t *ref = dslink_map_get(&respNode->resp_sub_streams, (void*)respPath); BrokerSubStream *bss; if (ref) { bss = ref->data; } else { bss = broker_stream_sub_init(); bss->respSid = broker_node_incr_sid(respNode); bss->remote_path = dslink_strdup(respPath); bss->respNode = (BrokerNode*)respNode; // a invalid qos value, so the newQos != qos, // which will send a new subscribe method to responder bss->respQos = 0xFF; dslink_map_set(&respNode->resp_sub_streams, dslink_str_ref(bss->remote_path), dslink_ref(bss, NULL)); dslink_map_set(&respNode->resp_sub_sids, dslink_int_ref(bss->respSid), dslink_ref(bss, NULL)); } subreq->stream = bss; dslink_map_set(&bss->reqSubs, dslink_ref(reqNode, NULL), dslink_ref(subreq, NULL)); broker_update_stream_qos(bss); if (bss->last_value) { broker_update_sub_req(subreq, bss->last_value); } }
static uint8_t set_virtual_permission(const char* path, VirtualDownstreamNode* node, json_t *json) { if (!path || *path == 0) { List *permissions = permission_list_load(json); permission_list_free(node->permissionList); node->permissionList = permissions; return 0; } else { const char* next = strstr(path, "/"); char* name; if (next) { name = dslink_calloc(next - path + 1, 1); memcpy(name, path, next-path); next ++; // remove '/' } else { name = (char*)path; } ref_t *ref = dslink_map_get(&node->childrenNode, name); VirtualDownstreamNode *child; if (ref && ref->data) { child = ref->data; } else { child = dslink_calloc(1, sizeof(VirtualDownstreamNode)); virtual_downstream_node_init(child); dslink_map_set(&node->childrenNode, dslink_str_ref(name), dslink_ref(child, NULL)); } return set_virtual_permission(next, child, json); } }
void broker_subscribe_local_nonexistent(const char *path, SubRequester *subreq) { Broker *broker = mainLoop->data; ref_t *ref = dslink_map_get(&broker->local_pending_sub, (char *) path); List *subs; if (ref) { subs = ref->data; } else { subs = dslink_calloc(1, sizeof(List)); list_init(subs); dslink_map_set(&broker->local_pending_sub, dslink_str_ref(path), dslink_ref(subs, subs_list_free)); } subreq->pendingNode = dslink_list_insert(subs, subreq); }
void broker_add_new_subscription(Broker *broker, SubRequester *subreq) { char *out = NULL; DownstreamNode * reqNode = subreq->reqNode; BrokerNode *respNode = broker_node_get(broker->root, subreq->path, &out); dslink_map_set(&reqNode->req_sub_paths, dslink_str_ref(subreq->path), dslink_ref(subreq, NULL)); dslink_map_set(&reqNode->req_sub_sids, dslink_int_ref(subreq->reqSid), dslink_ref(subreq, NULL)); if (!respNode) { if (dslink_str_starts_with(subreq->path, "/downstream/") || dslink_str_starts_with(subreq->path, "/upstream/")) { broker_subscribe_disconnected_remote(subreq->path, subreq); } else { broker_subscribe_local_nonexistent(subreq->path, subreq); } return; } if (respNode->type == REGULAR_NODE) { broker_handle_local_subscribe( respNode, subreq); } else { DownstreamNode *downNode = (DownstreamNode *)respNode; broker_subscribe_remote(downNode, subreq, out); } }
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; }