---
title: "Connecting"
description: "Guide to connecting the Aerospike C client via plaintext or PKI TLS, including configuration steps and code examples."
---

# Connecting

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

The `aerospike` object represents a single cluster. To connect to a cluster, you must configure an `aerospike` object and initialize the client. However, depending on how you wish to connect (plaintext versus encrypted with TLS), the steps you take to configure your `aerospike` object will differ.

## Connecting over plaintext connections

### Configuring the client

To configure the client to connect over a plaintext connection, initialize an `as_config` object to its default value using `as_config_init()`:

```cpp
as_config config;

as_config_init(&config);
```

You need at least one host configuration to seed the client. The client attempts to connect to each seed you specify, until it succeeds. Once successful, the host establishes a connection to the cluster and automatically discovers the remaining cluster nodes, if any.

```cpp
as_config_add_host(&config, "127.0.0.1", 3000);
```

::: note
You can call `as_config_add_host` as many times as necessary. You do **not** need to add a host for each machine in a cluster.
:::

### Initializing a client

Before connecting to the cluster, initialize an `aerospike` client object using your configuration.

```cpp
aerospike as;

aerospike_init(&as, &config);
```

On success, `aerospike_init` returns a pointer to the initialized `aerospike` object; otherwise it answers with NULL.

### Establishing a connection

After initializing an `aerospike` instance, you can connect to the cluster using `aerospike_connect`. Connecting might result in an error, so it is required to pass an `as_error` instance as an output parameter. Similar to exceptions in other programming languages, this allows the client library to provide additional context about the error.

::: tip
Whenever possible, try to keep instances of `as_error` on a call stack. Also, remember you can reuse a single `as_error` instance in a single call frame.
:::

```cpp
as_error err;

if (aerospike_connect(&as, &err) != AEROSPIKE_OK) {

    fprintf(stderr, "err(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);

}
```

The value of `err.code` equals the return code from `aerospike_connect`. If `AEROSPIKE_OK` is not the return value, an error occurred. Check the `err` object for information.

An `aerospike` object internally contains the cluster status and maintains the connection pools to the cluster. The application can reuse the `aerospike` object for database operations to a given cluster.

If the application needs to connect to multiple Aerospike clusters, it must create multiple `aerospike` objects, one for each cluster.

### Closing a connection

When the application no longer requires the client connections to the cluster, close the connection with `aerospike_close()`:

```cpp
as_error err;

if (aerospike_close(&as, &err) != AEROSPIKE_OK) {

    fprintf(stderr, "err(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);

}
```

### Cleaning up resources

Use `aerospike_destroy()` to destroy the client and release all of its resources:

```cpp
aerospike_destroy(&as);
```

## Connecting over a public key infrastructure (PKI) TLS Connection

Connecting over TLS requires you to perform all of the steps you’d normally perform for a plaintext connection. However, there are additional steps you need to perform in order to provide the required security information to establish a TLS encrypted session.

::: note
Connections over plain text or TLS can occur on any port you happen to have configured in your server settings. However, the convention is to use port 3000 for plaintext connections and 4333 for TLS-encrypted connections. The remainder of this example will also adhere to these conventions.
:::

### Basic configuration for the client

Start by initializing and adding the seed host to a configuration, as with a plaintext connection. Note that we use a different port for TLS connections.

```cpp
as_config config;

as_config_init(&config);

as_config_add_host(&config, "127.0.0.1", 4333);
```

### Initializing a client

Before connecting to the cluster, you need to initialize an `aerospike` client object using your configuration.

1.  You need to inform the Aerospike client that you are attempting to use TLS to connect.
    
    ```cpp
    as_config config;
    
    config.tls.enable = true;
    ```
    
2.  You’ll want to provide a CA certificate file suitable for the server you wish to connect to. How to acquire this certificate file is beyond the scope of this tutorial; however, if you need initial direction for learning more about this in a hands-on way, you may want to look into the [Aerolab](https://github.com/aerospike/aerolab) project. Aerolab makes deploying and managing clusters for educational purposes easier.
    
    ```cpp
    as_config config;
    
    as_config_tls_set_cafile(&config, "/home/project_acct/.config/aerospike/CA/cacert.pem");
    ```
    
    ::: note
    If you are given a directory with numerous CA certificate files, consider calling `as_config_tls_set_capath` instead of `as_config_tls_set_cafile` to point at the CA directory instead of a specific file. If you use both, the latter takes precedence.
    :::
    
3.  Iterate through all the hosts in the cluster, setting each host’s TLS name. Recall that attaching to a seed host allows the client to discover the topology of the cluster as a whole. However, it isn’t clear to the client how you wish to connect yet. The data retrieved thus assumes you’re planning on connecting over a plaintext connection. Since we desire a PKI connection, we must update the client’s knowledge of the host constellation to use TLS as well. You may recall that TLS configuration involves setting a “TLS name” to identify a given TLS configuration.
    
    ```cpp
    as_config config;
    
    for (int i = 0; i < config.hosts->capacity; i++) {
    
        as_host* host = (as_host*)as_vector_get(config.hosts, i);
    
        if (! host->tls_name) {
    
            host->tls_name = strdup("tls1");
    
        }
    
    }
    ```
    
4.  Resume the connection process exactly like we would a plaintext connection.
    
    ```cpp
    aerospike as;
    
    aerospike_init(&as, &config);
    
    if (aerospike_connect(&as, &err) != AEROSPIKE_OK) {
    
        fprintf(stderr, "err(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);
    
    }
    ```
    

### Closing a connection

When the application no longer requires the client connections to the cluster, close the connection with `aerospike_close()`:

```cpp
as_error err;

if (aerospike_close(&as, &err) != AEROSPIKE_OK) {

    fprintf(stderr, "err(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);

}
```

### Cleaning up resources

Use `aerospike_destroy()` to destroy the client and release all of its resources:

```cpp
aerospike_destroy(&as);
```

## C listing

The following example illustrates how to connect to a server over plaintext or PKI TLS connections, providing a more complete illustration of what real code should look like in practice. Depending on which command-line options you specify, it may perform either a plaintext or a PKI TLS connection.

```c
#include <errno.h>

#include <getopt.h>

#include <stdbool.h>

#include <stdint.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <aerospike/aerospike.h>

////// Parse command-line arguments

// The result of parsing arguments from the CLI.

typedef struct program_options_s {

  char* hostname;

  uint16_t port;

  bool tls_options_given;

  char* cafile;

  char* tls_name;

} program_options;

// If you alter any of these assignments, be sure to update

// `optstring` below as well.

enum {

  OPT_DONE = -1,

  OPT_HELP = 'h',

  OPT_HOST = 'r',

  OPT_PORT = 'p',

  OPT_CAFILE = 'a',

  OPT_TLS_NAME = 't',

};

static const struct option longopts[] = {

  {"help",         no_argument,       NULL, OPT_HELP},

  {"host",         required_argument, NULL, OPT_HOST},

  {"port",         required_argument, NULL, OPT_PORT},

  {"ca-file",      required_argument, NULL, OPT_CAFILE},

  {"cluster-name", required_argument, NULL, OPT_TLS_NAME},

  {NULL,           0,                 NULL, 0},

};

static const char* optstring = "h?r:p:a:t:";

static void

program_options_init(program_options* po)

{

  if(po) {

    memset(po, 0, sizeof(program_options));

    po->hostname = "127.0.0.1";

    po->port = 3000;

  }

}

static void

print_usage(const char* cmdname)

{

  printf("%s [options] "

         "-r|--host <remote host> "

         "-p|--port <port>\n\n", cmdname);

  printf("where [options] can be one or more of:\n");

  printf("  -?,-h  --help              Displays this message and quits.\n");

  printf("  -a     --ca-file <path>    Gives path to CA Certificate file\n");

  printf("  -t     --tls-name <name>   Gives the TLS cluster name\n");

  printf("\nNote that, at a minimum, -a and -t must be specified for "

         "TLS to work.\n");

}

void

program_options_parse(program_options* po, int argc, char* argv[])

{

  program_options_init(po);

  for (int done = 0; !done; ) {

    int res = getopt_long(argc, argv, optstring, longopts, NULL);

    switch(res) {

    default:

      printf("Unknown getopt_long() result: %u\n", res);

      // fall through intended.

    case OPT_DONE:

      done++;

      break;

    case '?':

    case OPT_HELP:

      print_usage(argv[0]);

      exit(EXIT_SUCCESS);

    case OPT_HOST:

      po->hostname = strdup(optarg);

      break;

    case OPT_PORT:

      errno = 0;

      unsigned long p = strtoul(optarg, NULL, 10);

      if(errno != 0) {

        perror("strtoul");

        exit(EXIT_FAILURE);

      }

      if(!((0 <= p) && (p < 65536))) {

        fprintf(stderr,

                "Port must fall between 0 "

                "and 65535 inclusive.\n");

        exit(EXIT_FAILURE);

      }

      po->port = (uint16_t)p;

      break;

    case OPT_CAFILE:

      po->cafile = strdup(optarg);

      break;

    case OPT_TLS_NAME:

      po->tls_name = strdup(optarg);

      break;

    }

  }

  // Set tls_options_given only if the minimum set of parameters

  // are given.

  po->tls_options_given = po->cafile && po->tls_name;

}

////// Example code

void

check_error(const char* operation, as_error* err)

{

  if (err->code != AEROSPIKE_OK) {

    fprintf(stderr,

            "Aerospike client failed while %s: "

            "err(%d) %s at [%s:%d]\n",

      operation,

      err->code, err->message, err->file, err->line);

    exit(EXIT_FAILURE);

  }

}

void

connect_to_aerospike(aerospike* as, program_options* po, as_error* err)

{

  as_config config;

  as_config_init(&config);

  // This adds the provided host as a seed.  This may yield a number

  // of additional hosts if the cluster size is greater than one.

  as_config_add_host(&config, po->hostname, po->port);

  if (po->tls_options_given) {

    config.tls.enable = true;

    as_config_tls_set_cafile(&config, po->cafile);

    // After discovering the complete set of hosts in the cluster,

    // we need to configure each of them with the TLS name we wish

    // to connect to.  Failing to do that will yield connection

    // failures when attempting to connect.

    for (int i = 0; i < config.hosts->capacity; i++) {

      as_host* host = (as_host*)as_vector_get(config.hosts, i);

      if( !host->tls_name) {

        host->tls_name = strdup(po->tls_name);

      }

    }

  }

  aerospike_init(as, &config);

  aerospike_connect(as, err);

  check_error("connecting", err);

}

int

main(int argc, char* argv[])

{

  program_options po;

  program_options_parse(&po, argc, argv);

  printf("Attempting to connect to host %s port %u\n", po.hostname, po.port);

  if (po.tls_options_given) {

    printf(" using TLS with the following settings:\n");

    printf("    CA File: %s\n", po.cafile);

    printf("   TLS Name: %s\n", po.tls_name);

  }

  else {

    printf("  without using TLS.\n");

  }

  aerospike as;

  as_error err;

  as_error_init(&err);

  connect_to_aerospike(&as, &po, &err);

  printf("Connection successful.\n");

  // ...

  printf("Now closing connection.\n");

  aerospike_close(&as, &err);

  check_error("closing connection", &err);

  return 0;

}
```