void permission_groups_free(PermissionGroups* groups) { if (groups->groups) { for (size_t i = 0; i < groups->groupLen; ++i) { dslink_free((void *)groups->groups[i]); } dslink_free(groups->groups); } }
static void broker_server_new_client(uv_poll_t *poll, int status, int events) { (void) status; (void) events; Server *server = poll->data; Client *client = dslink_calloc(1, sizeof(Client)); if (!client) { goto fail; } client->server = server; client->sock = dslink_socket_init(0); if (!client->sock) { dslink_free(client); goto fail; } if (mbedtls_net_accept(&server->srv, &client->sock->socket_ctx, NULL, 0, NULL) != 0) { log_warn("Failed to accept a client connection\n"); goto fail_poll_setup; } uv_poll_t *clientPoll = dslink_malloc(sizeof(uv_poll_t)); if (!clientPoll) { goto fail_poll_setup; } uv_loop_t *loop = poll->loop; if (uv_poll_init(loop, clientPoll, client->sock->socket_ctx.fd) != 0) { dslink_free(clientPoll); goto fail_poll_setup; } clientPoll->data = client; client->poll = clientPoll; uv_poll_start(clientPoll, UV_READABLE, broker_server_client_ready); log_debug("Accepted a client connection\n"); return; fail: { mbedtls_net_context tmp; mbedtls_net_init(&tmp); mbedtls_net_accept(&server->srv, &tmp, NULL, 0, NULL); mbedtls_net_free(&tmp); } return; fail_poll_setup: dslink_socket_free(client->sock); dslink_free(client); }
// permission list for node or virtual node void permission_list_free(List* list) { if (!list) { return; } dslink_list_foreach(list) { PermissionPair * pair = ((ListNode*)node)->value; dslink_free(pair->group); dslink_free(pair); } dslink_list_free(list); }
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; } }
void broker_close_link(RemoteDSLink *link) { if (!link) { return; } if (link->client) { dslink_socket_close_nofree(link->client->sock); } if (link->dsId) { log_info("DSLink `%s` has disconnected\n", (char *) link->dsId->data); } else { log_info("DSLink `%s` has disconnected\n", (char *) link->name); } ref_t *ref; if (link->isUpstream) { ref = dslink_map_get(link->broker->upstream->children, (void *) link->name); } else { ref = dslink_map_get(link->broker->downstream->children, (void *) link->name); } broker_remote_dslink_free(link); // it's possible that free link still rely on node->link to close related streams // so link need to be freed before disconnected from node if (ref) { DownstreamNode *node = ref->data; broker_dslink_disconnect(node); } dslink_free(link); }
void on_list_update(struct DSLink *link, ref_t *req_ref, json_t *resp) { (void) link; RequestHolder *holder = req_ref->data; json_t *updates = json_object_get(resp, "updates"); size_t index; json_t *value; const char* path = json_string_value(json_object_get(holder->req, "path")); printf("======= List %s =======\n", path); json_array_foreach(updates, index, value) { json_t *name = json_array_get(value, 0); json_t *val = json_array_get(value, 1); if (val->type == JSON_ARRAY || val->type == JSON_OBJECT) { char *data = json_dumps(val, JSON_INDENT(0)); printf("%s = %s\n", json_string_value(name), data); dslink_free(data); } else if (val->type == JSON_STRING) { printf("%s = %s\n", json_string_value(name), json_string_value(val)); } else if (val->type == JSON_INTEGER) { printf("%s = %lli\n", json_string_value(name), json_integer_value(val)); } else if (val->type == JSON_REAL) { printf("%s = %f\n", json_string_value(name), json_real_value(val)); } else if (val->type == JSON_NULL) { printf("%s = NULL\n", json_string_value(name)); } else if (val->type == JSON_TRUE) { printf("%s = true\n", json_string_value(name)); } else if (val->type == JSON_FALSE) { printf("%s = false\n", json_string_value(name)); } else { printf("%s = (Unknown Type)\n", json_string_value(name)); } }
static void get_virtual_permission(const char* path, VirtualDownstreamNode* node, const char **groups, PermissionLevel *levels, size_t glen) { if (node->permissionList) { if (get_current_permission(node->permissionList, groups, levels, glen)) { return; } } if (!path || *path == 0) { return; } 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); if (ref && ref->data) { VirtualDownstreamNode *child = ref->data; get_virtual_permission(next, child, groups, levels, glen); } if (name != path) { dslink_free(name); } }
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; }
void on_invoke_updates(struct DSLink *link, ref_t *req_ref, json_t *resp) { (void) link; (void) req_ref; char *data = json_dumps(resp, JSON_INDENT(2)); printf("Got invoke %s\n", data); dslink_free(data); }
static void broker_server_client_ready(uv_poll_t *poll, int status, int events) { (void) status; Client *client = poll->data; Server *server = client->server; if (events & UV_READABLE) { server->data_ready(client, poll->loop->data); if (client->sock->socket_ctx.fd == -1) { // The callback closed the connection dslink_socket_free(client->sock); dslink_free(client); client = NULL; uv_close((uv_handle_t *) poll, broker_free_handle); } } if (client && (events & UV_WRITABLE)) { RemoteDSLink *link = client->sock_data; if (link) { link->ws->write_enabled = 1; wslay_event_send(link->ws); } } }
void dslink_map_free(Map *map) { if (!(map && map->table)) { return; } dslink_map_entry_clear(map); dslink_free(map->table); }
static void subs_list_free(void *p) { List *subs = p; dslink_list_foreach_nonext(subs) { ListNode *entry = (ListNode *) node; entry->list = NULL; //avoid list_remove_node SubRequester *sub = entry->value; sub->pendingNode = NULL; ListNodeBase *tmp = node->next; if ((intptr_t) node != (intptr_t) subs) { dslink_free(node); } node = tmp; } dslink_free(subs); }
static void handle_conn(Broker *broker, HttpRequest *req, Socket *sock) { json_error_t err; json_t *body; { const char *start = strchr(req->body, '{'); const char *end = strrchr(req->body, '}'); if (!(start && end)) { goto exit; } body = json_loadb(start, end - start + 1, 0, &err); if (!body) { broker_send_internal_error(sock); goto exit; } } const char *dsId = broker_http_param_get(&req->uri, "dsId"); if (!dsId) { goto exit; } log_info("%s connecting \n", dsId); const char *token = broker_http_param_get(&req->uri, "token"); json_t *resp = broker_handshake_handle_conn(broker, dsId, token, body); json_decref(body); if (!resp) { broker_send_internal_error(sock); goto exit; } char *data = json_dumps(resp, JSON_INDENT(2)); json_decref(resp); if (!data) { broker_send_internal_error(sock); goto exit; } char buf[1024]; int len = snprintf(buf, sizeof(buf) - 1, CONN_RESP, (int) strlen(data), data); buf[len] = '\0'; dslink_free(data); dslink_socket_write(sock, buf, (size_t) len); exit: return; }
PermissionLevel get_permission(const char* path, BrokerNode* rootNode, RemoteDSLink *reqLink) { if (!rootNode->permissionList) { return PERMISSION_CONFIG; } if (*path != '/') { return PERMISSION_NONE; } size_t glen = reqLink->permission_groups.groupLen; PermissionLevel *levels = dslink_calloc(glen, sizeof(PermissionLevel)); get_node_permission(path+1, rootNode, reqLink->permission_groups.groups, levels, glen); PermissionLevel maxLevel = PERMISSION_NONE; for (size_t i = 0; i < glen; ++i) { if (levels[i] > maxLevel) { maxLevel = levels[i]; } } dslink_free(levels); return maxLevel; }
int dslink_ws_send_obj(wslay_event_context_ptr ctx, json_t *obj) { DSLink *link = ctx->user_data; uint32_t msg = dslink_incr_msg(link); json_t *jsonMsg = json_integer(msg); json_object_set(obj, "msg", jsonMsg); char *data = json_dumps(obj, JSON_PRESERVE_ORDER); if (!data) { return DSLINK_ALLOC_ERR; } dslink_ws_send(ctx, data); dslink_free(data); json_object_del(obj, "msg"); json_delete(jsonMsg); return 0; }
static char *dslink_str_replace_all_rep(const char *haystack, const char *needle, const size_t needleLen, const char *replacement, const size_t replacementLen, const int shouldDup) { char *start = strstr(haystack, needle); if (!start) { if (shouldDup) { return dslink_strdup(haystack); } else { return (char *) haystack; } } const size_t haystackLen = strlen(haystack); char *dup = dslink_malloc(haystackLen - needleLen + replacementLen + 1); if (!dup) { return NULL; } size_t len = start - haystack; memcpy(dup, haystack, len); memcpy(dup + len, replacement, replacementLen); len += replacementLen; size_t remainder = (haystack + haystackLen) - (start + needleLen); memcpy(dup + len, start + needleLen, remainder); dup[haystackLen - needleLen + replacementLen] = '\0'; if (!shouldDup) { dslink_free((char *) haystack); } return dslink_str_replace_all_rep(dup, needle, needleLen, replacement, replacementLen, 0); }
static int dslink_map_rehash_table(Map *map) { size_t oldCapacity = map->capacity; MapNode **oldTable = map->table; size_t newCapacity = oldCapacity * 2; MapNode **newTable = dslink_calloc(newCapacity, sizeof(MapNode*)); if (!newTable) { return DSLINK_ALLOC_ERR; } map->capacity = newCapacity; map->table = newTable; for (MapEntry *entry = (MapEntry *) map->list.head.next; (void *)entry != &map->list.head; entry = entry->next) { size_t len = map->key_len_calc(entry->key->data); size_t index = dslink_map_index_of_key(map, entry->key->data, len); MapNode *node = newTable[index]; if (node) { while (1) { MapNode *tmp = node->next; if (tmp == NULL) { break; } node = tmp; } node->next = entry->node; entry->node->prev = node; entry->node->next = NULL; } else { entry->node->next = NULL; entry->node->prev = NULL; newTable[index] = entry->node; } } dslink_free(oldTable); return 0; }
void virtual_downstream_node_free(VirtualDownstreamNode *pnode) { json_decref(pnode->meta); virtual_downstream_free_map(&pnode->childrenNode); permission_list_free(pnode->permissionList); dslink_free(pnode); }
static void handle_subscribe(RemoteDSLink *link, json_t *sub) { const char *path = json_string_value(json_object_get(sub, "path")); json_t *jSid = json_object_get(sub, "sid"); if (!(path && jSid)) { return; } PermissionLevel permissionOnPath = get_permission(path, link->broker->root, link); if (permissionOnPath < PERMISSION_READ) { return; } DownstreamNode *reqNode = link->node; uint32_t sid = (uint32_t) json_integer_value(jSid); json_t *jQos = json_object_get(sub, "qos"); uint8_t qos = 0; if (json_is_integer(jQos)) { qos = (uint8_t) json_integer_value(jQos); } // TODO check if sid or path already exist ref_t *idsub = dslink_map_get(&reqNode->req_sub_sids, &sid); ref_t *pathsub = dslink_map_get(&reqNode->req_sub_paths, (void*)path); if (idsub && pathsub && idsub->data == pathsub->data) { // update qos only SubRequester *reqsub = idsub->data; broker_update_sub_qos(reqsub, qos); return; } if (idsub) { // remove current sub; SubRequester *reqsub = idsub->data; broker_free_sub_requester(reqsub); } if (pathsub) { // update sid and qos on existing path; SubRequester *reqsub = pathsub->data; ref_t *pathidsub = dslink_map_remove_get(&reqNode->req_sub_sids, &reqsub->reqSid); if (pathidsub) { dslink_free(pathidsub); } reqsub->reqSid = sid; dslink_map_set(&reqNode->req_sub_sids, dslink_int_ref(sid), dslink_ref(reqsub, NULL)); broker_update_sub_qos(reqsub, qos); if (json_array_size(reqsub->qosQueue) > 0) { // send qos data broker_update_sub_req_qos(reqsub); } else if (reqsub->stream && reqsub->stream->last_value) { broker_update_sub_req(reqsub, reqsub->stream->last_value); } return; } SubRequester *subreq = broker_create_sub_requester(reqNode, path, sid, qos, NULL); if (qos & 2) { serialize_qos_queue(subreq, 0); } broker_add_new_subscription(link->broker, subreq); }
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; }
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; }
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; }
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; }
int dslink_handshake_connect_ws(Url *url, mbedtls_ecdh_context *key, const char *uri, const char *tempKey, const char *salt, const char *dsId, const char *token, Socket **sock) { *sock = NULL; int ret = 0; unsigned char auth[90]; if (tempKey && salt) if ((ret = dslink_handshake_gen_auth_key(key, tempKey, salt, auth, sizeof(auth))) != 0) { goto exit; } char req[512]; size_t reqLen; { char builtUri[256]; char * encodedDsId = dslink_str_escape(dsId); if (tempKey && salt) { snprintf(builtUri, sizeof(builtUri) - 1, "%s?auth=%s&dsId=%s", uri, auth, encodedDsId); } else { // trusted dslink snprintf(builtUri, sizeof(builtUri) - 1, "%s?dsId=%s&token=%s", uri, encodedDsId, token); } dslink_free(encodedDsId); char wsKey[32]; if ((ret = gen_ws_key(wsKey, sizeof(wsKey))) != 0) { goto exit; } reqLen = snprintf(req, sizeof(req), DSLINK_WS_REQ, builtUri, url->host, url->port, wsKey); } if ((ret = dslink_socket_connect(sock, url->host, url->port, url->secure)) != 0) { *sock = NULL; goto exit; } dslink_socket_write(*sock, req, reqLen); char buf[1024]; size_t len = 0; memset(buf, 0, sizeof(buf)); while (len < (sizeof(buf) - 1)) { // Read 1 byte at a time to ensure that we don't accidentally // read web socket data int read = dslink_socket_read(*sock, buf + len, 1); if (read <= 0) { goto exit; } if (buf[len++] == '\n' && strstr(buf, "\r\n\r\n")) { if (!strstr(buf, "101 Switching Protocols")) { ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; } if (strstr(buf, "401 Unauthorized")) { ret = DSLINK_HANDSHAKE_UNAUTHORIZED; } goto exit; } } // Failed to find the end of the HTTP response ret = DSLINK_HANDSHAKE_INVALID_RESPONSE; exit: if (ret != 0 && *sock) { dslink_socket_close(*sock); *sock = NULL; } return ret; }
static void free_stream(void* p) { Stream *stream = p; dslink_free((void*)stream->path); dslink_free(stream); }