A C client for the [NATS messaging system](https://nats.io).
Go [here](http://nats-io.github.io/nats.c) for the online documentation,
and check the [frequently asked questions](https://github.com/nats-io/nats.c#faq).
This NATS Client implementation is heavily based on the [NATS GO Client](https://github.com/nats-io/nats.go). There is support for Mac OS/X, Linux and Windows (although we don't have specific platform support matrix).
There are several package managers with NATS C client library available. If you know one that is not in this list, please submit a PR to add it!
- [Homebrew](https://github.com/Homebrew/homebrew-core) The "cnats" formula is [here](https://github.com/Homebrew/homebrew-core/blob/master/Formula/cnats.rb)
- [vcpkg](https://vcpkg.io) The "cnats" port is [here](https://github.com/microsoft/vcpkg/tree/master/ports/cnats)
## Building
First, download the source code:
```
git clone git@github.com:nats-io/nats.c.git .
```
To build the library, use [CMake](https://cmake.org/download/). Note that by default the NATS Streaming API will be built and included in the NATS library.
See below if you do not want to build the Streaming related APIs.
Make sure that CMake is added to your path. If building on Windows, open a command shell from the Visual Studio Tools menu, and select the appropriate command shell (x64 or x86 for 64 or 32 bit builds respectively). You will also probably need to run this with administrator privileges.
Create a `build` directory (any name would work) from the root source tree, and `cd` into it. Then issue this command for the first time:
```
cmake ..
```
In some architectures, you may experience a compilation error for `mutex.c.o` because there is no support
for the assembler instruction that we use to yield when spinning trying to acquire a lock.
You may get this sort of build error:
```
/tmp/cc1Yp7sD.s: Assembler messages:
/tmp/cc1Yp7sD.s:302: Error: selected processor does not support ARM mode `yield'
src/CMakeFiles/nats_static.dir/build.make:542: recipe for target 'src/CMakeFiles/nats_static.dir/unix/mutex.c.o' failed
```
If that's the case, you can solve this by enabling the `NATS_BUILD_NO_SPIN` flag (or use `-DNATS_NO_SPIN` if you compile without CMake):
```
cmake .. -DNATS_BUILD_NO_SPIN=ON
```
If you had previously built the library, you may need to do a `make clean`, or simply delete and re-create the build directory before executing the cmake command.
To build on Windows, you would need to select the build generator. For instance, to select `nmake`, you would run:
```
cmake .. -G "NMake Makefiles"
```
Running `cmake -h` would give you the list of possible options and all the generator names.
Alternatively, you can run the GUI version. From that same *build* command shell, start the GUI:
```
c:\program files (x86)\CMake\bin\cmake-gui.exe
```
If you started with an empty build directory, you would need to select the source and build directory, then click `Configure`. Here, you will be able to select from the drop-down box the name of the build generator. When done, click `Generate`. Then you can go back to your command shell, or Visual Studio and build.
To modify some of the build options, you need to edit the cache and rebuild.
```
make edit_cache
```
Note that if you build on Windows and have selected "NMake Makefiles", replace all following references to `make` with `nmake`.
Editing the cache allows you to select the build type (Debug, Release, etc), the architecture (64 or 32bit), and so on.
The default target will build everything, that is, the static and shared NATS libraries and also the examples and the test program. Each are located in their respective directories under your build directory: `src`, `examples` and `test`.
```
make install
```
Will copy both the static and shared libraries in the folder `install/lib` and the public headers in `install/include`.
## TLS Support
By default, the library is built with TLS support. You can disable this from the cmake gui `make edit_cache` and switch the `NATS_BUILD_WITH_TLS` option to `OFF`, or pass the option directly to the `cmake` command:
```
cmake .. -DNATS_BUILD_WITH_TLS=OFF
```
Starting `2.0.0`, when building with TLS/SSL support, the server certificate's expected hostname is always verified. It means that the hostname provided in the URL(s) or through the option `natsOptions_SetExpectedHostname()` will be used to check the hostname present in the certificate. Prior to `2.0.0`, the hostname would be verified *only* if the option `natsOptions_SetExpectedHostname()` was invoked.
Although we recommend leaving the new default behavior, you can restore the previous behavior by building the library with this option off:
```
cmake .. -DNATS_BUILD_TLS_FORCE_HOST_VERIFY=OFF
```
The NATS C client is built using APIs from the [OpenSSL](https://github.com/openssl/openssl) library. By default we use `3.0+` APIs. Since OpenSSL `1.0.2` is no longer supported, starting with NATS C Client `v3.6.0` version, the CMake variable `NATS_BUILD_TLS_USE_OPENSSL_1_1_API` is now set to `ON` by default (if you are setting up a new environment) and will use OpenSSL APIs from `1.1+`/`3.0+` APIs. You will still be able to compile with the OpenSSL `1.0.2` library by setting this CMake option to `OFF`:
```
cmake .. -DNATS_BUILD_TLS_USE_OPENSSL_1_1_API=OFF
```
The variable `NATS_BUILD_TLS_USE_OPENSSL_1_1_API` is deprecated, meaning that in the future this option will simply be removed and only OpenSSL `3.0+` APIs will be used. The code in the library using older OpenSSL APIs will be removed too.
Note that the variable `NATS_BUILD_WITH_TLS_CLIENT_METHOD` that was deprecated in `v2.0.0` has now been removed.
Since the NATS C client dynamically links to the OpenSSL library, you need to make sure that you are then running your application against an OpenSSL 1.1+/3.0+ library.
### Link statically
If you want to link to the static OpenSSL library, you need to delete the `CMakeCache.txt` and regenerate it with the additional option:
Then call `make` (or equivalent depending on your platform) and this should ensure that the library (and examples and/or test suite executable) are linked against the OpenSSL library, if it was found by CMake.
## Building with Streaming
When building the library with Streaming support, the NATS library uses the [libprotobuf-c](https://github.com/protobuf-c/protobuf-c) library.
When cmake runs for the first time (or after removing `CMakeCache.txt` and calling `cmake ..` again), it is looking for the libprotobuf-c library. If it does not find it, a message is printed and the build process fails.
CMake searches for the library in directories where libraries are usually found. However, if you want to specify a specific directory where the library is located, you need to do this:
If you don't want to build the NATS Streaming APIs to be included in the NATS library:
```
cmake .. -DNATS_BUILD_STREAMING=OFF
```
## Building with Libsodium
When using the new NATS 2.0 security features, the library needs to sign some "nonce" sent by the server during a connect or reconnect.
We use [Ed25519](https://ed25519.cr.yp.to/) public-key signature. The library comes with some code to perform the signature.
In most case, it will be fine, but if performance is an issue (especially if you plan to use the `natsConnection_Sign()` function a lot), you will have the option to build with the [Libsodium](https://github.com/jedisct1/libsodium) library.
Follow instructions on how to install the libsodium library [here](https://download.libsodium.org/doc/).
On macOS, you could use `brew`:
```
brew install libsodium
```
On Linux, you could use `apt-get`
```
apt-get install libsodium-dev
```
Once installed, you can rebuild the NATS C client by first enabling the use of the libsodium library:
```
cmake .. -DNATS_BUILD_USE_SODIUM=ON
```
If you have the libsodium library installed in a non standard location that CMake cannot find, you can specify the location of this directory:
On platforms where `valgrind` is available, you can run the tests with memory checks.
Here is an example:
```
make test ARGS="-T memcheck"
```
Or, you can invoke directly the `ctest` program:
```
ctest -T memcheck -V -I 1,4
```
The above command would run the tests with `valgrind` (`-T memcheck`), with verbose output (`-V`), and run the tests from 1 to 4 (`-I 1,4`).
If you add a test to `test/test.c`, you need to add it into the `allTests` array. Each entry contains a name, and the test function. You can add it anywhere into this array.
Build you changes:
```
make
[ 44%] Built target nats
[ 88%] Built target nats_static
[ 90%] Built target nats-publisher
[ 92%] Built target nats-queuegroup
[ 94%] Built target nats-replier
[ 96%] Built target nats-requestor
[ 98%] Built target nats-subscriber
Scanning dependencies of target testsuite
[100%] Building C object test/CMakeFiles/testsuite.dir/test.c.o
Linking C executable testsuite
[100%] Built target testsuite
```
Now regenerate the list by invoking the test suite without any argument:
```
./test/testsuite
Number of tests: 77
```
This list the number of tests added to the file `list.txt`. Move this file to the source's test directory.
```
mv list.txt ../test/
```
Then, refresh the build:
```
cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ivan/nats.c/build
```
You can use the following environment variables to influence the testsuite behavior.
When running with memory check, timing changes and overall performance is slower. The following variable allows the testsuite to adjust some of values used during the test:
```
export NATS_TEST_VALGRIND=yes
```
On Windows, it would be `set` instead of `export`.
When running the tests in verbose mode, the following environment variable allows you to see the server output from within the test itself. Without this option, the server output is silenced:
```
export NATS_TEST_KEEP_SERVER_OUTPUT=yes
```
If you want to change the default server executable name (`nats-server.exe`) or specify a specific location, use this environment variable:
```
set NATS_TEST_SERVER_EXE=c:\test\nats-server.exe
```
# Documentation
The public API has been documented using [Doxygen](http://www.stack.nl/~dimitri/doxygen/).
To generate the documentation, go to the `doc` directory and type the following command:
```
doxygen DoxyFile.NATS.Client
```
If you toggle the build of the Streaming APIs, and the documentation is no longer matching
what is being built, you can update the documentation by switching the `NATS_UPDATE_DOC` build flag and rebuild the documentation.
From the build directory:
```
cmake .. -DNATS_UPDATE_DOC=ON
make
cd <nats.crootdir>/doc
doxygen DoxyFile.NATS.Client
```
The generated documentation will be located in the `html` directory. To see the documentation, point your browser to the file `index.html` in that directory.
Go [here](http://nats-io.github.io/nats.c) for the online documentation.
The source code is also quite documented.
# NATS Client
## Important Changes
This section lists important changes such as deprecation notices, etc...
### Version `2.0.0`
This version introduces the security concepts used by NATS Server `2.0.0` and therefore aligns with the server version. There have been new APIs introduced, but the most important change is the new default behavior with TLS connections:
* When establishing a secure connection, the server certificate's hostname is now always verified, regardless if the user has invoked `natsOptions_SetExpectedHostname()`. This may break applications that were for instance using an IP to connect to a server that had only the hostname in the certificate. This can be solved by changing your application to use the hostname in the URL or make use of `natsOptions_SetExpectedHostname()`. If this is not possible, you can restore the old behavior by building the library with the new behavior disabled. See #tls-support for more information.
* This repository used to include precompiled libraries of [libprotobuf-c](https://github.com/protobuf-c/protobuf-c) for macOS, Linux and Windows along with the header files (in the `/pbuf` directory).
We have now removed this directory and require that the user installs the libprotobuf-c library separately. See the [building instructions](#building) to specify the library location if CMake cannot find it directly.
### Version `1.8.0`
* The `natsConnStatus` enum values have been prefixed with `NATS_CONN_STATUS_`. If your application is
not using referencing any original value, such as `CONNECTED` or `CLOSED`, etc.. then there is nothing
that you need to do. If you do, you have two options:
* Replace all references from the orignal values to the new value (adding the prefix)
* Compile the library with the option to use the original values (no prefix). Edit the CMake cache
and turn on the option `NATS_BUILD_NO_PREFIX_CONNSTS`. This can be done this way from the build directory:
`cmake .. -DNATS_BUILD_NO_PREFIX_CONNSTS=ON`
## Getting Started
The `examples/getstarted` directory has a set of simple examples that are fully functional, yet very simple.
The goal is to demonstrate how easy to use the API is.
A more complex set of examples are in `examples/` directory and can also be used to benchmark the client library.
## Basic Usage
Note that for simplicity, error checking is not performed here.
```c
natsConnection *nc = NULL;
natsSubscription *sub = NULL;
natsMsg *msg = NULL;
// Connects to the default NATS Server running locally
natsConnection_ConnectTo(&nc, NATS_DEFAULT_URL);
// Connects to a server with username and password
// Create a Stream. If you are not interested in the returned jsStreamInfo object,
// you can pass NULL.
js_AddStream(NULL, js, &cfg, NULL, &jerr);
// Update a Stream
cfg.MaxBytes = 8;
js_UpdateStream(NULL, js, &cfg, NULL, &jerr);
// Delete a Stream
js_DeleteStream(js, "ORDERS", NULL, &jerr);
```
## KeyValue
**EXPERIMENTAL FEATURE! We reserve the right to change the API without necessarily bumping the major version of the library.**
A KeyValue store is a materialized view based on JetStream. A bucket is a stream and keys are subjects within that stream.
Some features require NATS Server `v2.6.2`, so we recommend that you use the latest NATS Server release to have a better experience.
The new objects and APIs are full documented in the online [documentation](http://nats-io.github.io/nats.c/group__kv_group.html).
### KeyValue Management
Example of how to create a KeyValue store:
```c
jsCtx *js = NULL;
kvStore *kv = NULL;
kvConfig kvc;
// Assume we got a JetStream context in `js`...
kvConfig_Init(&kvc);
kvc.Bucket = "KVS";
kvc.History = 10;
s = js_CreateKeyValue(&kv, js, &kvc);
// Do some stuff...
// This is to free the memory used by `kv` object,
// not delete the KeyValue store in the server
kvStore_Destroy(kv);
```
This shows how to "bind" to an existing one:
```c
jsCtx *js = NULL;
kvStore *kv = NULL;
// Assume we got a JetStream context in `js`...
s = js_KeyValue(&kv, ks, "KVS");
// Do some stuff...
// This is to free the memory used by `kv` object,
// not delete the KeyValue store in the server
kvStore_Destroy(kv);
```
This is how to delete a KeyValue store in the server:
```c
jsCtx *js = NULL;
// Assume we got a JetStream context in `js`...
s = js_DeleteKeyValue(js, "KVS");
```
### KeyValue APIs
This is how to put a value for a given key:
```c
kvStore *kv = NULL;
uint64_t rev = 0;
// Assume we got a kvStore...
s = kvStore_PutString(&rev, kv, "MY_KEY", "my value");
// If the one does not care about getting the revision, pass NULL:
s = kvStore_PutString(NULL, kv, "MY_KEY", "my value");
```
The above places a value for a given key, but if instead one wants to make sure that the value is placed for the key only if it never existed before, one would call:
```c
// Same note than before: if "rev" is not needed, pass NULL:
s = kvStore_CreateString(&rev, kv, "MY_KEY", "my value");
```
One can update a key if and only if the last revision in the server matches the one passed to this API:
```c
// This would update the key "MY_KEY" with the value "my updated value" only if the current revision (sequence number) for this key is 10.
s = kvStore_UpdateString(&rev, kv, "MY_KEY", "my updated value", 10);
// Once done with the entry, we need to destroy it to release memory.
// This is NOT deleting the key from the server.
kvEntry_Destroy(e);
```
This is how to purge a key:
```c
kvStore *kv = NULL;
// Assume we got a kvStore...
s = kvStore_Purge(kv, "MY_KEY");
```
This will delete the key in the server:
```c
kvStore *kv = NULL;
// Assume we got a kvStore...
s = kvStore_Delete(kv, "MY_KEY");
```
To create a "watcher" for a given key:
```c
kvWatcher *w = NULL;
kvWatchOptions o;
// Assume we got a kvStore...
// Say that we are not interested in getting the
// delete markers...
// Initialize a kvWatchOptions object:
kvWatchOptions_Init(&o);
o.IgnoreDeletes = true;
// Create the watcher
s = kvStore_Watch(&w, kv, "foo.*", &o);
// Check for error..
// Now get updates:
while (some_condition)
{
kvEntry *e = NULL;
// Wait for the next update for up to 5 seconds
s = kvWatcher_Next(&e, w, 5000);
// Do something with the entry...
// Destroy to release memory
kvEntry_Destroy(e);
}
// When done with the watcher, it needs to be destroyed to release memory:
kvWatcher_Destroy(w);
```
To get the history of a key:
```c
kvEntryList l;
int i;
// The list is defined on the stack and will be initilized/updated by this call:
s = kvStore_History(&l, kv, "MY_KEY", NULL);
for (i=0; i<l.Count;i++)
{
kvEntry *e = l.Entries[i];
// Do something with the entry...
}
// When done with the list, call this to free entries and the content of the list.
kvEntryList_Destroy(&l);
// In order to set a timeout to get the history, we need to do so through options:
kvWatchOptions o;
kvWatchOptions_Init(&o);
o.Timeout = 5000; // 5 seconds.
s = kvStore_History(&l, kv, "MY_KEY", &o);
```
This is how you would get the keys of a bucket:
```c
kvKeysList l;
int i;
// If no option is required, pass NULL as the last argument.
s = kvStore_Keys(&l, kv, NULL);
// Check error..
// Go over all keys:
for (i=0; i<l.Count;i++)
printf("Key: %s\n", l.Keys[i]);
// When done, list need to be destroyed.
kvKeysList_Destroy(&l);
// If option need to be specified:
kvWatchOptions o;
kvWatchOptions_Init(&o);
o.Timeout = 5000; // 5 seconds.
s = kvStore_Keys(&l, kv, &o);
```
## Headers
Headers are available when connecting to servers at version 2.2.0+.
They closely resemble http headers. They are a map of key/value pairs, the value being an array of strings.
Headers allow users to add meta information about a message without interfering with the message payload.
Note that if an application attempts to send a message with a header when connected to a server that does not understand them, the publish call will return the error `NATS_NO_SERVER_SUPPORT`.
There is an API to know if the server currently connected to supports headers:
```c
natsStatus s = natsConnection_HasHeaderSupport(conn);
if (s == NATS_NO_SERVER_SUPPORT)
// deal with server not supporting this feature.
```
If the server understands headers but is about to deliver the message to a client that doesn't, the headers are stripped off so that the older clients can still receive the messsage.
It is important to have all client and servers to a version that support headers if applications rely on headers.
For more details on the headers API, please get the example: `examples/getstarted/headers.c`.
## Wildcard Subscriptions
The `*` wildcard matches any token, at any level of the subject:
All subscriptions with the same queue name will form a queue group. Each message will be delivered to only one subscriber per queue group, using queue sematics. You can have as many queue groups as you wish. Normal subscribers will continue to work as expected.
(Note that the library needs to be built with TLS support - which is by default - for these APIs to work. See the Build chapter on how to build with or without TLS for more details).
An SSL/TLS connection is configured through the use of `natsOptions`. Depending on the level of security you desire, it can be as simple as setting the secure boolean to true on the `natsOptions_SetSecure()` call.
Even with full security (client verifying server certificate, and server requiring client certificates), the setup involves only a few calls.
```c
// Here is the minimum to create a TLS/SSL connection:
// Create an options object.
natsOptions_Create(&opts);
// Set the secure flag.
natsOptions_SetSecure(opts, true);
// You may not need this, but suppose that the server certificate
// is self-signed and you would normally provide the root CA, but
// don't want to. You can disable the server certificate verification
// like this:
natsOptions_SkipServerVerification(opts, true);
// Connect now...
natsConnection_Connect(&nc, opts);
// That's it! On success you will have a secure connection with the server!
(...)
// This example shows what it takes to have a full SSL configuration,
// including server expected's hostname, root CA, client certificates
// and specific ciphers to use.
// Create an options object.
natsOptions_Create(&opts);
// Set the secure flag.
natsOptions_SetSecure(opts, true);
// For a server with a trusted chain built into the client host,
// simply designate the server name that is expected. Without this
// call, the server certificate is still verified, but not the
// You can also specify preferred ciphers if you want.
natsOptions_SetCiphers(opts, "-ALL:HIGH");
// Then simply pass the options object to the connect call:
natsConnection_Connect(&nc, opts);
// That's it! On success you will have a secure connection with the server!
```
## New Authentication (Nkeys and User Credentials)
This requires server with version >= 2.0.0
NATS servers have a new security and authentication mechanism to authenticate with user credentials and Nkeys. The simplest form is to use the helper option `natsOptions_SetUserCredentialsFromFiles()`.
```c
// Retrieve both user JWT and NKey seed from single file `user.creds`.
s = natsOptions_SetUserCredentialsFromFiles(opts, "user.creds", NULL);
if (s == NATS_OK)
s = natsConnection_Connect(&nc, opts);
```
With this option, the library will load the user JWT and NKey seed from a single file. Note that the library wipes the buffers used to read the files.
If you prefer to store the JWT and seed in two distinct files, use this form instead:
```c
// Retrieve the user JWT from the file `user.jwt` and the seed from the file `user.nk`.
s = natsOptions_SetUserCredentialsFromFiles(opts, "user.jwt", "user.nk");
if (s == NATS_OK)
s = natsConnection_Connect(&nc, opts);
```
You can also set the callback handlers and manage challenge signing directly.
```c
/*
* myUserJWTCb is a callback that is supposed to return the user JWT.
* An optional closure can be specified.
* mySignatureCB is a callback that is presented with a nonce and is
* responsible for returning the signature for this nonce.
* An optional closure can be specified.
*/
s = natsOptions_SetUserCredentialsCallbacks(opts, myUserJWTCb, NULL, mySignatureCb, NULL);
if (s == NATS_OK)
s = natsConnection_Connect(&nc, opts);
```
For NKey authentication, it is possible to specify the public NKey and the file containing the corresponding NKey seed. On connect, the library will load this file to look for the NKey seed and use it to sign the nonce sent by the server. The library takes care of clearing the memory where the seed is copied as soon
as the nonce is signed.
```c
s = natsOptions_SetNKeyFromSeed(opts, "UDXU4RCSJNZOIQHZNWXHXORDPRTGNJAHAHFRGZNEEJCPQTT2M7NLCNF4", "seed.nk");
if (s == NATS_OK)
s = natsConnection_Connect(&nc, opts);
```
The "seed.nk" file contains the NKey seed (private key). Here is an example:
Finally, it is possible to specify the public NKey and the signature callback. The public key will be sent to the server and the provided callback is responsible for signing the server's nonce. When the server receives the signed nonce, it can check that it was signed poperly using the provided public key.
```c
/*
* myPublicKey is the user's public key, which will be sent to the server.
* mySignatureCB is a callback that is presented with a nonce and is
* responsible for returning the signature for this nonce.
* An optional closure can be specified.
*/
s = natsOptions_SetNKey(opts, myPublicKey, mySignatureCb, NULL);
if (s == NATS_OK)
s = natsConnection_Connect(&nc, opts);
```
The signature callback can use any crypto library to sign the nonce, but also the provided `nats_Sign()` function.
```c
natsStatus
mySignatureCb(
char **customErrTxt,
unsigned char **signature,
int *signatureLength,
const char *nonce,
void *closure)
{
// This approach requires to provide the seed (private key).
// Hardcoding it in the application (like in this example) may not be really safe.
You can sign any content and get the signature in return. The connection must have been created with the `natsOptions_SetUserCredentialsFromFiles()` option for that to work.
```c
s = natsOptions_Create(&opts);
if (s == NATS_OK)
s = natsOptions_SetUserCredentialsFromFiles(opts, "user.creds", NULL);
s = natsConnection_Sign(nc, content, contentLen, sig);
if (s == NATS_OK)
{
// Do something with signature...
}
```
## Advanced Usage
Flushing a connection ensures that any data buffered is flushed (sent to) the NATS Server.
```c
// Flush connection to server, returns when all messages have been processed.
natsConnection_Flush(nc);
printf("All clear!\n");
// Same as above but with a timeout value, expressed in milliseconds.
s = natsConnection_FlushTimeout(nc, 1000);
if (s == NATS_OK)
printf("All clear!\n");
else if (s == NATS_TIMEOUT)
printf("Flushed timed out!\n");
else
printf("Error during flush: %d - %s\n", s, natsStatus_GetText(s));
```
Auto-unsubscribe allows a subscription to be automatically removed when the subscriber has received a given number of messages. This is used internally by the `natsConnection_Request()` call.
Subscriptions can be drained. This ensures that the interest is removed from the server but that all messages that were internally queued are processed.
```c
// This call does not block.
natsSubscription_Drain(sub);
// If you want to wait for the drain to complete, call this
// and specify a timeout. Zero or negative to wait for ever.
natsSubscription_WaitForDrainCompletion(sub, 0);
```
Connections can be drained. This process will first put all registered subscriptions in drain mode and prevent any new subscription from being created. When all subscriptions are drained, the publish calls are drained (by the mean of a connection flush) and new publish calls will fail at this point. Then the connection is closed.
```c
// Use default timeout of 30 seconds.
// But this call does not block. Use natsOptions_SetClosedCB() to be notified
// that the connection is closed.
natsConnection_Drain(nc);
// To specify a timeout for the operation to complete, after which the connection
// is forcefully closed. Here is an exampel of a timeout of 10 seconds (10,000 ms).
natsConnection_DrainTimeout(nc, 10000);
```
You can have multiple connections in your application, mixing subscribers and publishers.
The use of `natsOptions` allows you to specify options used by the `natsConnection_Connect()` call. Note that the `natsOptions` object that is passed to this call is cloned, whhich means that any modification done to the options object will not have any effect on the connected connection.
```c
natsOptions *opts = NULL;
// Create an options object
natsOptions_Create(&opts);
// Set some properties, starting with the URL to connect to:
natsOptions_SetURL(opts, "nats://host1:4222");
// Set a callback for asynchronous errors. This is useful when having an asynchronous
// subscriber, which would otherwise have no other way of reporting an error.
natsOptions_SetErrorHandler(opts, asyncCb, NULL);
// Connect using those options:
natsConnection_Connect(&nc, opts);
// Destroy the options object to free memory. The object was cloned by the connection,
// so the options can be safely destroyed.
natsOptions_Destroy(opts);
```
As we have seen, all callbacks have a `void *closure` parameter. This is useful when the callback needs to perform some work and need a reference to some object. When setting up the callback, you can specify a pointer to that object.
```c
// Our object definition
typedef struct __Errors
{
int count;
} Errors;
(...)
int
main(int argc, char **argv)
{
// Declare an 'Errors' object on the stack.
Errors asyncErrors;
// Initialize this object
memset(&asyncErrors, 0, sizeof(asyncErrors);
// Create a natsOptions object.
(...)
// Set the error callback, and pass the address of our Errors object.
For each connection, the `NATS` library creates a thread reading data from the socket. Publishing data results in the data being appended to a buffer, which is 'flushed' from a timer callback or in place when the buffer reaches a certain size. Flushing means that we write to the socket (and the socket is in blocking-mode).
If you have multiple connections running in your process, the number of threads will increase (because each connection uses a thread for receiving data from the socket). If this becomes an issue, or if you are already using an event notification library, you can instruct the `NATS` library to use that event library instead of using a thread to do the reads, and directly writing to the socket when data is published.
This works by setting the event loop and various callbacks through the `natsOptions_SetEventLoop()` API. Depending of the event loop you are using, you then have extra API calls to make. The API is in the `adapters` directory and is documented.
We provide adapters for two event notification libraries: [libevent](https://github.com/libevent/libevent), and [libuv](https://github.com/libuv/libuv).
The callback `onMsg` that you have registered will be triggered as usual when data becomes available.
Where it becomes tricky is when publishing data. Indeed, publishing is merely putting data in a buffer, and it is the event library that will notify a callback that write to the socket should be performed. For that, the event loop needs to be 'running'.
So if you publish from the thread where the event loop is running, you need to 'run' the loop after each (or a number) of publish calls in order for data to actually be sent out. Alternatively, you can publish from a different thread than the thread running the event loop.
The above is important to keep in mind regarding calls that are doing request-reply. They should not be made from the thread running the event loop. Here is an example of such calls:
```
natsConnection_Request()
natsConnection_Flush()
natsConnection_FlushTimeout()
...
```
Indeed, since these calls publish data and wait for a 'response', if you execute then in the event loop thread (or while the loop is not 'running'), then data will not be sent out. Calls will fail to get a response and timeout.
For `natsConnection_Request()`, use the `natsConnection_PublishRequest()` instead, and have a subscriber for the response registered.
For others, asynchronous version of these calls should be made available.
See examples in the `examples` directory for complete usage.
## FAQ
Here are some of the frequently asked questions:
<b>Where do I start?</b>
There are several resources that will help you get started using the NATS C Client library.
<br>
The `examples/getstarted` directory contains very basic programs that use
the library for simple functions such as sending a message or setting up a subscription.
<br>
The `examples` directory itself contains more elaborated examples that include error
handling and more advanced APIs. You will also find examples to that show the use
of the NATS C Client library and external event loops.
<b>What about support for platform XYZ?</b>
We support platforms that are available to us for development and testing. This is currently
limited to Linux, macOS and Windows. Even then, there may be OS versions that you may have
problem building with and we will gladly accept PRs to fix the build process as long as it
does not break the ones we support!
<b>How do I build?</b>
We use cmake since it allows cross-platforms builds. This works for us. You are free to
create your own makefile or Windows solution. If you want to use cmake, follow these
// Unsubscribe (note that for non durable subscriptions, Unsubscribe() and Close() are the same
stanSubscription_Unsubscribe(sub);
// Close connection
stanConnection_Close(sc);
```
### Streaming Subscriptions
NATS Streaming subscriptions are similar to NATS subscriptions, but clients may start their subscription at an earlier point in the message stream, allowing them to receive messages that were published before this client registered interest.
The options are described with examples below:
```
// Create a Subscription Options:
stanSubOptions *subOpts = NULL;
stanSubOptions_Create(&subOpts);
// Subscribe starting with most recently published value
stanSubOptions_StartWithLastReceived(subOpts);
// OR: Receive all stored messages
stanSubOptions_DeliverAllAvailable(subOpts);
// OR: Receive messages starting at a specific sequence number
stanSubOptions_StartAtSequence(subOpts, 22);
// OR: Start at messages that were stored 30 seconds ago. Value is expressed in milliseconds.
Replay of messages offers great flexibility for clients wishing to begin processing at some earlier point in the data stream.
However, some clients just need to pick up where they left off from an earlier session, without having to manually track their position in the stream of messages.
Durable subscriptions allow clients to assign a durable name to a subscription when it is created.
Doing this causes the NATS Streaming server to track the last acknowledged message for that clientID + durable name, so that only messages since the last acknowledged message will be delivered to the client.