Ejemplo n.º 1
0
static
void dslink_map_entry_clear(Map *map) {
    for (MapEntry *entry = (MapEntry *) map->list.head.next;
         (void *) entry != &map->list.head;) {
        MapEntry *tmp = entry->next;
        dslink_decref(entry->key);
        dslink_decref(entry->value);
        dslink_free(entry->node);
        dslink_free(entry);
        entry = tmp;
    }
}
Ejemplo n.º 2
0
ref_t *dslink_map_removel_get(Map *map, void *key, size_t len) {
    if (!map || map->locked) {
        return NULL;
    }
    size_t index = dslink_map_index_of_key(map, key, len);
    for (MapNode *node = map->table[index]; node != NULL; node = node->next) {
        if (map->cmp(node->entry->key->data, key, len) != 0) {
            continue;
        }
        if (node->prev == NULL) {
            if (node->next) {
                MapNode *tmp = node->next;
                tmp->prev = NULL;
                map->table[index] = tmp;
            } else {
                map->table[index] = NULL;
            }
        } else {
            node->prev->next = node->next;
            if (node->next) {
                node->next->prev = node->prev;
            }
        }

        ref_t *ref = node->entry->value;
        dslink_decref(node->entry->key);
        list_free_node(node->entry);
        dslink_free(node);
        map->size--;
        return ref;
    }
    return NULL;
}
Ejemplo n.º 3
0
void dslink_map_removel(Map *map, void *key, size_t len) {
    if (!map || map->locked) {
        return;
    }
    ref_t *ref = dslink_map_removel_get(map, key, len);
    if (ref) {
        dslink_decref(ref);
    }
}
Ejemplo n.º 4
0
int dslink_map_set(Map *map, ref_t *key, ref_t *value) {
    if (!(key && value)) {
        return 1;
    }
    int ret;
    const float loadFactor = (float) map->size / map->capacity;
    if (loadFactor >= map->max_load_factor) {
        if ((ret = dslink_map_rehash_table(map)) != 0) {
            return ret;
        }
    }

    MapNode *node = NULL;
    if ((ret = dslink_map_get_raw_node(map, &node, key)) != 0) {
        if (ret == DSLINK_ALLOC_ERR) {
            return ret;
        }
    }

    dslink_decref(node->entry->value);
    node->entry->value = value;
    return 0;
}
Ejemplo n.º 5
0
int broker_msg_handle_invoke(RemoteDSLink *link, json_t *req) {
    json_t *reqRid = json_object_get(req, "rid");
    json_t *reqPath = json_object_get(req, "path");
    if (!(reqRid && reqPath)) {
        return 1;
    }
    json_t *maxPermitJson = json_object_get(req, "permit");
    PermissionLevel maxPermit = PERMISSION_CONFIG;
    if (json_is_string(maxPermitJson)) {
        maxPermit = permission_str_level(json_string_value(maxPermitJson));
    }

    const char *path = json_string_value(reqPath);
    char *out = NULL;
    BrokerNode *node = broker_node_get(link->broker->root, path, &out);
    if (!node) {
        broker_utils_send_closed_resp(link, req, "disconnected");
        return 0;
    }

    Broker *broker = mainLoop->data;

    PermissionLevel permissionOnPath = get_permission(path, broker->root, link);
    if (permissionOnPath > maxPermit) {
        permissionOnPath = maxPermit;
    }

    if (permissionOnPath == PERMISSION_NONE) {
        broker_utils_send_closed_resp(link, req, "permissionDenied");
        return 0;
    }
    if (node->type == REGULAR_NODE) {
        json_t *invokableJson = json_object_get(node->meta, "$invokable");

        PermissionLevel level = permission_str_level(json_string_value(invokableJson));
        if (level > permissionOnPath) {
            broker_utils_send_closed_resp(link, req, "permissionDenied");
        } else if (node->on_invoke) {
            node->on_invoke(link, node, req, maxPermit);
        }
        return 0;
    } else if (node->type != DOWNSTREAM_NODE) {
        // Unknown node type
        broker_utils_send_closed_resp(link, req, "disconnected");
        return 0;
    }

    DownstreamNode *ds = (DownstreamNode *) node;
    uint32_t rid = broker_node_incr_rid(ds);

    if (!ds->link) {
        broker_utils_send_closed_resp(link, req, "disconnected");
        return 0;
    }

    BrokerInvokeStream *s = broker_stream_invoke_init();

    s->responder_rid = rid;
    s->responder = ds->link;
    s->resp_close_cb = remote_invoke_resp_disconnected;

    s->requester_rid = (uint32_t) json_integer_value(reqRid);
    s->requester = link;
    s->req_close_cb = remote_invoke_req_closed;

    ref_t *refStream = dslink_ref(s, NULL);
    dslink_map_set(&ds->link->responder_streams, dslink_int_ref(rid),
                   refStream);

    ref_t *findref = dslink_map_remove_get(&link->requester_streams, &s->requester_rid);
    if (findref) {
        BrokerStream *oldstream = findref->data;
        if (oldstream->req_close_cb) {
            oldstream->req_close_cb(oldstream, link);
        }
        broker_stream_free(oldstream);
        dslink_decref(findref);
    }
    dslink_map_set(&link->requester_streams,
                   dslink_int_ref(s->requester_rid),
                   dslink_incref(refStream));

    send_invoke_request(ds, req, rid, out, permissionOnPath);
    return 0;
}
Ejemplo n.º 6
0
static
int dslink_map_get_raw_node(Map *map, MapNode **node, ref_t *key) {
    int ret = 0;
    size_t len = map->key_len_calc(key->data);
    size_t index = dslink_map_index_of_key(map, key->data, len);
    *node = map->table[index];
    if (!(*node)) {
        *node = map->table[index] = dslink_malloc(sizeof(MapNode));
        if (*node) {
            (*node)->entry = dslink_malloc(sizeof(MapEntry));
            if (!(*node)->entry) {
                map->table[index] = NULL;
                dslink_free(*node);
                *node = NULL;
                goto exit;
            }
            (*node)->entry->node = *node;
            (*node)->entry->key = key;
            (*node)->entry->value = NULL;

            (*node)->next = NULL;
            (*node)->prev = NULL;
        }
    } else {
        while (1) {
            if (map->cmp((*node)->entry->key->data, key->data, len) == 0) {
                dslink_decref((*node)->entry->key);
                (*node)->entry->key = key;
                return 1;
            }
            MapNode *tmp = (*node)->next;
            if (tmp == NULL) {
                tmp = dslink_malloc(sizeof(MapNode));
                if (!tmp) {
                    *node = NULL;
                    break;
                }
                tmp->entry = dslink_malloc(sizeof(MapEntry));
                if (!tmp->entry) {
                    dslink_free(*node);
                    *node = NULL;
                    break;
                }

                tmp->entry->key = key;
                tmp->entry->value = NULL;
                tmp->entry->node = tmp;

                tmp->next = NULL;
                tmp->prev = *node;

                (*node)->next = tmp;
                *node = tmp;
                break;
            }
            *node = tmp;
        }
    }

exit:
    if (!(*node)) {
        return DSLINK_ALLOC_ERR;
    }
    map->size++;
    list_insert_node(&map->list, (*node)->entry);
    return ret;
}
Ejemplo n.º 7
0
int dslink_request_handle(DSLink *link, json_t *req) {
    const char *method = json_string_value(json_object_get(req, "method"));
    if (!method) {
        return 1;
    }

    if (strcmp(method, "list") == 0) {
        const char *path = json_string_value(json_object_get(req, "path"));
        DSNode *node = dslink_node_get_path(link->responder->super_root, path);
        return dslink_response_list(link, req, node);
    } else if (strcmp(method, "subscribe") == 0) {
        json_t *paths = json_object_get(req, "paths");
        json_t *rid = json_object_get(req, "rid");
        return dslink_response_sub(link, paths, rid);
    } else if (strcmp(method, "unsubscribe") == 0) {
        json_t *sids = json_object_get(req, "sids");
        json_t *rid = json_object_get(req, "rid");
        return dslink_response_unsub(link, sids, rid);
    } else if (strcmp(method, "invoke") == 0) {
        const char *path = json_string_value(json_object_get(req, "path"));
        DSNode *node = dslink_node_get_path(link->responder->super_root, path);
        if (node && node->on_invocation) {
            Stream *stream = dslink_malloc(sizeof(Stream));
            if (!stream) {
                return 1;
            }
            stream->type = INVOCATION_STREAM;
            stream->path = dslink_strdup(node->path);

            ref_t *stream_ref = dslink_ref(stream, free_stream);

            json_t *jsonRid = json_object_get(req, "rid");
            json_t *params = json_object_get(req, "params");
            node->on_invocation(link, node, jsonRid, params, stream_ref);

            if (stream->unused != 1) {
                dslink_decref(stream_ref);
            } else {
                ref_t *rid = dslink_ref(dslink_malloc(sizeof(uint32_t)), dslink_free);
                {
                    uint32_t r = (uint32_t) json_integer_value(jsonRid);
                    *((uint32_t *) rid->data) = r;
                }

                if (dslink_map_set(link->responder->open_streams,
                                   rid,
                                   stream_ref) != 0) {
                    dslink_free(rid);
                    dslink_free(stream_ref);
                    free_stream(stream);
                    return 1;
                }
            }
        }
    } else if (strcmp(method, "set") == 0) {
        const char *path = json_string_value(json_object_get(req, "path"));
        json_t *value = json_object_get(req, "value");
        DSNode *node = dslink_node_get_path(link->responder->super_root, path);
        
        if (node) {
            ref_t *writable_ref = dslink_map_get(node->meta_data, "$writable");
            if (writable_ref && json_is_string((json_t*) writable_ref->data)) {
                if (node->on_value_set) {
                    node->on_value_set(link, node, value);
                } else {
                    dslink_node_update_value(link, node, value);
                }
            }
        }
    } else if (strcmp(method, "close") == 0) {
        json_t *rid = json_object_get(req, "rid");
        uint32_t ridi = (uint32_t) json_integer_value(rid);
        ref_t *stream_ref = dslink_map_remove_get(link->responder->open_streams, &ridi);
        if (stream_ref) {
            Stream *stream = stream_ref->data;

            DSNode *node = NULL;

            if (stream->path) {
                node = dslink_node_get_path(link->responder->super_root, stream->path);
            }

            if (stream->on_close != NULL) {
                stream->on_close(link, node, stream);
            }

            if (stream->type == LIST_STREAM) {
                dslink_map_remove(link->responder->list_subs, (void *) stream->path);
            }

            dslink_decref(stream_ref);
        }
    } else {
        log_warn("Unrecognized method: %s\n", method);
    }
    return 0;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
0
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;
}