nabto_client_connection_connect()

DESCRIPTION

Connect to a device.

If this future returns ok, a connection is created between the client and the device. If the connection is made using a relay channel, the connection will be tried to be upgraded to a p2p connection in the background, after this future is resolved.

A connection is made over channels, a channel can be a direct udp connection or a relayed udp connection. If no channel can be established between the client and the device the error NABTO_CLIENT_EC_NO_CHANNEL is returned. This reason for this can be many and to find the specific root cause the function nabto_client_connection_get_info must be consulted.

Since we try many different channels for the communication only errors which is not supposed to happen if the software is used appropriately are reported. E.g. If the device is not connected to the server, it is not logged as an error. If the server_key specified is invalid, then it’s logged as an error.

DECLARATION

NABTO_CLIENT_DECL_PREFIX void NABTO_CLIENT_API
nabto_client_connection_connect(NabtoClientConnection* connection, NabtoClientFuture* future)

PARAMETERS

connection:
[in] The connection.
future:
[in] The future.

RETURN VALUES

NABTO_CLIENT_EC_OK iff connection is ok and connected to the device. NABTO_CLIENT_EC_INVALID_STATE if the connection is missing required options. NABTO_CLIENT_EC_NO_CHANNELS if no channels could be created. see nabto_client_connection_get_local_channel_error_code and nabto_client_connection_get_remote_channel_error_code or nabto_client_connection_get_info for what went wrong. NABTO_CLIENT_EC_NOT_CONNECTED if the the connection failed for some unspecified reason. NABTO_CLIENT_EC_INTERNAL_ERROR if the device encountered an internal error during the connect attempt. This is most likely due to no more connection resources available in the device.

EXAMPLES

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

#include <nabto/nabto_client.h>

struct ClientContext {
    NabtoClient* client;
    NabtoClientConnection* connection;
    NabtoClientFuture* future;
};

static void connect();
static void cb_connected(NabtoClientFuture *future, NabtoClientError ec, void *data);
static void print_connection_info(struct ClientContext* ctx);
static void print_connection_type(struct ClientContext* ctx);
static void cleanup(struct ClientContext* ctx);

static int finished = 0;

int main(int argc, char** argv) {
    struct ClientContext* ctx = (struct ClientContext*)malloc(sizeof(struct ClientContext));
    memset(ctx, 0, sizeof(struct ClientContext));
    ctx->client = nabto_client_new();
    connect(ctx);
    while (!finished) {
        // do stuff here while the connect future asynchonously resolves - or use
        // nabto_client_future_wait for synchronous behavior instead of setting async callback
        sleep(1);
        print_connection_type(ctx);
    }
    nabto_client_free(ctx->client);
    return 0;
}

static void connect(struct ClientContext* ctx) {
    const char* clientPrivateKey =
        "-----BEGIN EC PARAMETERS-----"
        "BggqhkjOPQMBBw=="
        "-----END EC PARAMETERS-----"
        "-----BEGIN EC PRIVATE KEY-----"
        "MHcCAQEEIPzp7QHuqMZLXMmigdEtUsJ/sgE0IKRONnAHhmB1/OBdoAoGCCqGSM49"
        "AwEHoUQDQgAEHOb4U+Jervfn/cSe+zg7SdhdFbxVkYWZU35dsycrGYhsOcD8jyYI"
        "gvjMfjwJ6wNV3aFXyWdPdfY/brfP/dyjUw=="
        "-----END EC PRIVATE KEY-----";
    ctx->connection = nabto_client_connection_new(ctx->client);

    nabto_client_connection_set_private_key(ctx->connection, clientPrivateKey);
    nabto_client_connection_set_product_id(ctx->connection, "pr-xruwhj1");
    nabto_client_connection_set_device_id(ctx->connection, "de-1cgtwfm3");
    nabto_client_connection_set_server_url(ctx->connection, "https://pr-xruwhj1.clients.nabto.net");
    nabto_client_connection_set_server_key(ctx->connection, "sk-33c11dece0517aaa1837b5e49fe1bdd1");
    nabto_client_connection_set_application_name(ctx->connection, "DemoApp");
    nabto_client_connection_set_application_version(ctx->connection, "1.0.0");

    ctx->future = nabto_client_future_new(ctx->client);
    nabto_client_connection_connect(ctx->connection, ctx->future);
    nabto_client_future_set_callback(ctx->future, cb_connected, ctx);
}

static void cb_connected(NabtoClientFuture *future, NabtoClientError ec, void *data) {
    struct ClientContext* ctx = (struct ClientContext*)data;
    if (ec == NABTO_CLIENT_EC_OK) {
        printf("Connection attempt succeeded.\n");
        print_connection_info(ctx);
        print_connection_type(ctx);
        // TODO: use connection - for instance, open a stream or send a CoAP request, close connection when done
    } else {
        printf("Connection attempt failed, ec=%d.\n", ec);
        print_connection_info(ctx);
        cleanup(ctx);
    }
}

static void print_connection_info(struct ClientContext* ctx) {
    char* json;
    if (!ctx->connection) {
        return;
    }
    if (nabto_client_connection_get_options(ctx->connection, &json) == NABTO_CLIENT_EC_OK) {
        printf("Connection options: %s\n", json);
        nabto_client_string_free(json);
    } else {
        printf("Could not get connection options.\n");
    }
    if (nabto_client_connection_get_info(ctx->connection, &json) == NABTO_CLIENT_EC_OK) {
        printf("Connection info: %s\n", json);
        nabto_client_string_free(json);
    } else {
        printf("Could not get connection info.\n");
    }
}

static void print_connection_type(struct ClientContext* ctx) {
    if (!ctx->connection) {
        return;
    }
    NabtoClientConnectionType type;
    NabtoClientError ec = nabto_client_connection_get_type(ctx->connection, &type);
    const char* typeStr;
    if (ec == NABTO_CLIENT_EC_OK) {
        switch (type) {
        case NABTO_CLIENT_CONNECTION_TYPE_RELAY: typeStr = "RELAY"; break;
        case NABTO_CLIENT_CONNECTION_TYPE_DIRECT: typeStr = "DIRECT"; break;
        default: assert(!"Unexpected connection type");
        }
    } else {
        typeStr = "not determined";
    }
    printf("Connection type is currently %s\n", typeStr);
}

static void cleanup(struct ClientContext* ctx) {
    if (ctx->connection) {
        nabto_client_connection_close(ctx->connection, ctx->future);
        if (ctx->future) {
            nabto_client_future_wait(ctx->future);
        }
        nabto_client_connection_free(ctx->connection);
        ctx->connection = NULL;
    }
    if (ctx->future) {
        nabto_client_future_free(ctx->future);
        ctx->future = NULL;
    }
    finished = 1;
}