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); } } }
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); }
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; }