Beispiel #1
0
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);
    }
}
Beispiel #2
0
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);
    }
}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
    }
}
Beispiel #5
0
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;
}