Configuration API for C SDK
C complete configuration reference for building real-time applications on PubNub: context lifecycle, the pubnub_config_t field reference, retry policy, proxy, and TCP keepalive.
Every C SDK context is configured through a single struct, pubnub_config_t. Populate it with pubnub_config_defaults() and then override the fields your application needs, then pass it to one of two lifecycle functions to obtain a context: pubnub_create() (heap-allocated) or pubnub_init() (caller-provided memory). Both accept the same pubnub_config_t, but they differ in how they take ownership of the strings inside it. Read Initialization before writing any configuration code.
String ownership depends on which lifecycle function you call
pubnub_init() borrows every const char* field in pubnub_config_t. The memory backing subscribe_key, publish_key, user_id, and every other string field must stay valid for as long as the context exists. pubnub_create() deep-copies those same fields, so the caller can free or reuse the original buffers immediately after the call returns.
The six provider pointer fields (allocator, transport, serialization, platform, crypto_module, logger) are always borrowed, on both paths. Mixing these two rules up is the single most common configuration mistake with this SDK.
Initialization
Method(s)
The C SDK exposes two mutually exclusive ways to obtain a pubnub_context_t. Use exactly one of them per context.
#include <stddef.h>
#include <pubnub/client.h>
pubnub_config_t pubnub_config_defaults(void);
pubnub_context_t* pubnub_create(const pubnub_config_t* config);
void pubnub_destroy(pubnub_context_t* ctx);
pubnub_res_t pubnub_init(pubnub_context_t* ctx, const pubnub_config_t* config);
void pubnub_deinit(pubnub_context_t* ctx);
size_t pubnub_context_size(void);
| Function | Parameters | Returns |
|---|---|---|
pubnub_config_defaults | none | A pubnub_config_t with five fields set: transaction_timeout_ms, non_transaction_timeout_ms, tcp_keepalive (enabled, 60 s / 20 s / 3 probes), retry_configuration (exponential retry for subscribe requests only, every other endpoint group excluded), and log_level (PUBNUB_LOG_LEVEL_INFO). It does not set subscribe_key, publish_key, secret_key, or user_id. You still set those yourself. |
pubnub_create | config: required, borrowed for the duration of the call, deep-copied into the new context | A heap-allocated pubnub_context_t*, or NULL if config is NULL, fails validation, or allocation fails. Not compiled in when PUBNUB_CFG_NO_HEAP=1. |
pubnub_destroy | ctx: consumed, safe to pass NULL | void. ctx must not be used after this call. |
pubnub_init | ctx: required, caller-owned memory of at least pubnub_context_size() bytes. config: required, borrowed for the context's lifetime | PUBNUB_OK, or an error code (see Error responses) |
pubnub_deinit | ctx: borrowed, safe to pass NULL, an uninitialized context, or an already-deinitialized context | void. Does not free ctx's memory. The caller owns that. |
pubnub_context_size | none | The number of bytes pubnub_init needs at the memory ctx points to. Always greater than 0. |
Header: #include <pubnub/client.h>
Types: pubnub_config_t, pubnub_context_t, pubnub_res_t
Prerequisite: call pubnub_config_defaults() first, then set at minimum subscribe_key and user_id before calling pubnub_create/pubnub_init.
Ownership / lifetime: pubnub_init borrows every const char* config field. pubnub_create deep-copies them. Provider pointer fields are always borrowed. A context obtained from pubnub_create is heap-owned by the SDK until pubnub_destroy. A context obtained from pubnub_init lives in memory the caller owns and must keep valid until pubnub_deinit.
Blocking: synchronous. None of these functions perform network I/O.
No heap, no pubnub_create
pubnub_create() and pubnub_destroy() are compiled out entirely when PUBNUB_CFG_NO_HEAP=1, the default for the embedded CMake profile. On a no-heap build, use pubnub_init()/pubnub_deinit() with caller-provided memory, shown below. See Environment Setup for build profiles.
Sample code
Heap-allocated context, using pubnub_create()/pubnub_destroy():
#include <stddef.h>
#include <pubnub/client.h>
int main(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.publish_key = "demo";
cfg.user_id = "my_unique_user_id";
pubnub_context_t* ctx = pubnub_create(&cfg);
if (ctx == NULL) {
/* config was NULL, failed validation, or allocation failed */
return 1;
}
show all 21 linesCaller-provided memory, using pubnub_init()/pubnub_deinit(). Required on builds with PUBNUB_CFG_NO_HEAP=1:
#include <stddef.h>
#include <stdint.h>
#include <pubnub/client.h>
#include <pubnub/pubnub_compat.h>
static PUBNUB_ALIGNAS(max_align_t) uint8_t s_ctx_mem[PUBNUB_CONTEXT_SIZE];
int main(void)
{
if (sizeof(s_ctx_mem) < pubnub_context_size()) {
/* PUBNUB_CONTEXT_SIZE is stale relative to this build; enlarge the buffer */
return 1;
}
pubnub_context_t* ctx = (pubnub_context_t*)s_ctx_mem;
show all 30 linesPUBNUB_ALIGNAS(max_align_t) on the static buffer is required: without it, casting a plain uint8_t[] (natural alignment 1) to a pubnub_context_t* is undefined behavior and can fault on strictly-aligned targets. See Embedded and no-heap targets for the full story.
Returns
pubnub_create returns a pubnub_context_t* (or NULL on failure). pubnub_init returns a pubnub_res_t. PUBNUB_OK means the context is ready to use.
Error responses
| Value | Returned by | Meaning | Recovery |
|---|---|---|---|
PUBNUB_OK | pubnub_init | Context initialized successfully. | none needed |
PUBNUB_ERR_INVALID_ARGUMENT | pubnub_init | ctx/config is NULL, subscribe_key/user_id is NULL or empty, or pubnub_init was called twice on the same context without an intervening pubnub_deinit. | Fix the caller-side argument, or call pubnub_deinit before re-initializing. |
PUBNUB_ERR_PROVIDER_MISSING | pubnub_init, pubnub_create | A supplied allocator, transport, serialization, or platform provider struct is missing a mandatory vtable entry. | Supply the missing vtable function, or leave the field NULL to use the compiled-in default. |
PUBNUB_ERR_OUT_OF_MEMORY | pubnub_init, pubnub_create | An internal allocation (request pool, pending queue, pipeline middleware) failed during setup. Any partial allocation is rolled back. | Reduce concurrent contexts/buffers, or supply a larger/alternate allocator. |
PUBNUB_ERR_INTERNAL | pubnub_init | A provider's own init() callback returned failure. Already-initialized providers are rolled back in reverse order. | Inspect the failing provider's init() implementation. |
pubnub_create signals the same first three failure classes by returning NULL instead of a pubnub_res_t. For the full pubnub_res_t catalog, see Status Events.
Teardown and outstanding futures
Both pubnub_destroy and pubnub_deinit join any background thread, then deliver PUBNUB_ERR_CANCELLED to every outstanding future's callback, then release resources. After either call returns, no further callbacks fire for that context. If you hold a pubnub_future_t across a pubnub_destroy/pubnub_deinit call, expect it to complete with PUBNUB_ERR_CANCELLED.
Configuration options
pubnub_config_t has 26 top-level fields: 20 value and string fields, plus 6 provider pointer fields. Every field is immutable after the context is created or initialized, except user_id, auth_token, origin, log_level, and dns_primary/dns_secondary (changed together as a pair), which have dedicated runtime setters covered in Runtime updates.
String fields follow the ownership rule from Initialization: borrowed by pubnub_init, deep-copied by pubnub_create. Provider pointer fields are always borrowed, regardless of which lifecycle function you use.
Identity and keys
| Parameter | Ownership | Mutable after init |
|---|---|---|
subscribe_key *Type: const char*Default: none, rejected if NULL/"" | borrowed / deep-copied | No |
publish_keyType: const char*Default: NULL | borrowed / deep-copied | No |
secret_keyType: const char*Default: NULL | borrowed / deep-copied | No |
pnsdk_suffixType: const char*Default: NULL (no suffix appended) | borrowed / deep-copied | No |
pnsdk_overrideType: const char*Default: NULL (compile-time SDK identifier unchanged) | borrowed / deep-copied | No |
user_id *Type: const char*Default: none, rejected if NULL/"" | borrowed / deep-copied | Yes, via pubnub_set_user_id() |
auth_tokenType: const char*Default: NULL | borrowed / deep-copied | Yes, via pubnub_set_auth_token() |
user_id must uniquely identify the user or device that connects to PubNub.
It's a UTF-8 encoded string of up to 92 alphanumeric characters.
publish_key is required only for publish operations and Access Manager signing. secret_key is required only for Access Manager signing.
pnsdk_override is for wrapper-SDK authors, not application code. When set, it completely replaces the compile-time SDK identifier in the pnsdk query parameter sent on every request, instead of leaving it in place and appending after it the way pnsdk_suffix does. Use it if you're building a higher-level SDK on top of this C SDK (for example, a Unity or Unreal Engine wrapper) and need PubNub to see your own product identity rather than PubNub-C.
Network
| Parameter | Ownership | Mutable after init |
|---|---|---|
originType: const char*Default: NULL/"" resolves to the compile-time origin (ps.pndsn.com by default) | borrowed / deep-copied (the resolved default is deep-copied too, even under pubnub_create) | Yes, via pubnub_set_origin() |
dns_primaryType: const char*Default: NULL (system-discovered DNS servers) | borrowed / deep-copied | Yes, via pubnub_set_dns_servers(), together with dns_secondary |
dns_secondaryType: const char*Default: NULL | borrowed / deep-copied | Yes, via pubnub_set_dns_servers(), together with dns_primary |
transaction_timeout_msType: unsigned int (ms)Default: 0 resolves to a compile-time default (10000 ms), floor of 1000 ms | value | No |
non_transaction_timeout_msType: unsigned int (ms)Default: 0 resolves to a compile-time default (310000 ms), only meaningful when subscribe is compiled in, floor of 1000 ms | value | No |
proxyType: pubnub_proxy_config_tDefault: zero-initialized struct → PUBNUB_PROXY_NONE (no proxy) | value (string sub-fields follow the same borrow/deep-copy rule) | No |
tcp_keepaliveType: pubnub_tcp_keepalive_config_t | value | No |
To request a custom origin, contact support and follow the request process.
Presence
| Parameter | Ownership | Mutable after init |
|---|---|---|
presence_timeoutType: uint32_t (seconds)Default: 0 → server default (300 s) | value | No |
heartbeat_intervalType: uint32_t (seconds)Default: 0 disables automatic client-side heartbeats entirely | value | No |
filter_expressionType: const char*Default: NULL (no filter) | borrowed / deep-copied | No, immutable even by the field's own doc comment |
suppress_leave_eventsType: uint8_t (0/1)Default: 0, leave events are sent | value | No |
presence_timeout and heartbeat_interval control how the server tracks client presence. Both are ignored at runtime when the SDK is built without presence support. filter_expression restricts subscribe delivery to messages that match a filter. See Publish messages for filter expression syntax.
There is no field or callback on pubnub_config_t that reports heartbeat success or failure back to your application. Automatic heartbeat is entirely fire-and-forget: the SDK sends it on the schedule these two fields describe, and nothing in the public API tells you whether any individual heartbeat succeeded.
Leaving heartbeat_interval at its default disables automatic heartbeat
heartbeat_interval at 0 (its default) disables automatic client-side heartbeats entirely. There is no auto-computed fallback derived from presence_timeout. This is exactly what pubnub_config_defaults() produces, since it touches neither field. To get automatic heartbeat, explicitly set heartbeat_interval to a nonzero value yourself.
Retry
| Parameter | Ownership | Mutable after init |
|---|---|---|
retry_configurationType: pubnub_retry_configuration_tDefault: zero-initialized struct → PUBNUB_RETRY_NONE (no automatic retries) | value | No |
Full field breakdown in Retry and reconnection.
Two different defaults, depending on how you build the config
A zero-initialized pubnub_config_t (for example = {0}, or a pubnub_init()-based context you didn't run through pubnub_config_defaults()) leaves retry_configuration.policy at PUBNUB_RETRY_NONE: no automatic retry at all. pubnub_config_defaults() sets policy to PUBNUB_RETRY_EXPONENTIAL, but also sets excluded_endpoints to every endpoint group except subscribe. The net effect of calling pubnub_config_defaults() is exponential retry on subscribe only, with publish, presence, message storage, channel groups, App Context, message reactions, and Access Manager requests all excluded. PUBNUB_RETRY_LINEAR is never a default on either path. It's an opt-in value you set yourself.
Logging
| Parameter | Ownership | Mutable after init |
|---|---|---|
log_levelType: pubnub_log_level_tDefault: zero-init → PUBNUB_LOG_LEVEL_NONE, pubnub_config_defaults() → PUBNUB_LOG_LEVEL_INFO | value | Yes, via pubnub_set_log_level() |
Setting log_level at config time takes effect before the first log line the SDK emits during pubnub_create()/pubnub_init() itself. Calling pubnub_set_log_level() afterward has the same effect from that point on. See Logging for the full level catalog and the custom logger interface.
Provider pointers
| Parameter | Ownership | Mutable after init |
|---|---|---|
allocatorType: pubnub_allocator_provider_t*Default: NULL → compiled-in default allocator | always borrowed | No |
transportType: pubnub_transport_provider_t*Default: NULL → compiled-in default transport | always borrowed | No |
serializationType: pubnub_serialization_provider_t*Default: NULL → compiled-in default serialization | always borrowed | No |
platformType: pubnub_platform_provider_t*Default: NULL → compiled-in default platform layer | always borrowed | No |
crypto_moduleType: pubnub_crypto_module_t*Default: NULL → payload encryption disabled, deliberately with no fallback default | borrowed, caller manages the module's lifetime | No |
loggerType: pubnub_logger_provider_t*Default: NULL → only the built-in default logger is registered | always borrowed | No, but more loggers can be added post-init with pubnub_logger_add() |
Full discussion in Providers.
Retry and reconnection
Method(s)
Header: #include <pubnub/client.h>
Types: pubnub_retry_configuration_t, pubnub_retry_policy_t, pubnub_endpoint_group_t
Feature flag: ignored at runtime when the SDK is built with PUBNUB_ENABLE_RETRY=0.
| Parameter | Description |
|---|---|
policyType: pubnub_retry_policy_tDefault: PUBNUB_RETRY_NONE on zero-init, PUBNUB_RETRY_EXPONENTIAL via pubnub_config_defaults() | PUBNUB_RETRY_NONE, PUBNUB_RETRY_LINEAR, or PUBNUB_RETRY_EXPONENTIAL |
delay_msType: unsigned intDefault: 0 → compile-time default (2000 ms) | Linear: delay between retries. Exponential: base delay. |
maximum_delay_msType: unsigned intDefault: 0 → compile-time default (150000 ms) | Ignored for the linear policy. |
maximum_retryType: unsigned intDefault: 0 → compile-time default per policy (10 for linear, 6 for exponential) | Documented maximum: 10. |
excluded_endpointsType: unsigned int (bitmask)Default: 0 → retry all endpoint groups | Bitwise OR of pubnub_endpoint_group_t values, below. |
pubnub_endpoint_group_t values, one bit per endpoint family:
| Value | Bit |
|---|---|
PUBNUB_ENDPOINT_MESSAGE_SEND | 0x01 |
PUBNUB_ENDPOINT_SUBSCRIBE | 0x02 |
PUBNUB_ENDPOINT_PRESENCE | 0x04 |
PUBNUB_ENDPOINT_MESSAGE_STORAGE | 0x08 |
PUBNUB_ENDPOINT_CHANNEL_GROUPS | 0x10 |
PUBNUB_ENDPOINT_APP_CONTEXT | 0x20 |
PUBNUB_ENDPOINT_MESSAGE_REACTIONS | 0x40 |
PUBNUB_ENDPOINT_PAM | 0x80 |
PUBNUB_ENDPOINT_FILES | 0x100 |
Sample code
#include <pubnub/client.h>
static void configure_retry(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.user_id = "my_unique_user_id";
/* Retry a failed request up to 5 times, 2 seconds apart, but never retry
publishes or history fetches — only subscribe and everything else */
cfg.retry_configuration.policy = PUBNUB_RETRY_LINEAR;
cfg.retry_configuration.delay_ms = 2000;
cfg.retry_configuration.maximum_retry = 5;
cfg.retry_configuration.excluded_endpoints =
PUBNUB_ENDPOINT_MESSAGE_SEND | PUBNUB_ENDPOINT_MESSAGE_STORAGE;
show all 16 linesThe policy/delay/retry-count lines follow the pubnub_retry_configuration_t field definitions. The excluded_endpoints line follows the OR-ed form shown in the header's own @code example.
Returns
None. retry_configuration takes effect the next time the context retries a request. It has no separate return value.
Proxy configuration
Method(s)
Header: #include <pubnub/proxy.h>
Types: pubnub_proxy_config_t, pubnub_proxy_type_t, pubnub_proxy_auth_t
Feature flag: the proxy field exists regardless of build configuration, but proxy support is compiled in only when PUBNUB_ENABLE_PROXY=1.
| Parameter | Description |
|---|---|
typeType: pubnub_proxy_type_tDefault: PUBNUB_PROXY_NONE | Also: PUBNUB_PROXY_HTTP_CONNECT (RFC 7231 §4.3.6), PUBNUB_PROXY_SOCKS5 (RFC 1928), or PUBNUB_PROXY_AUTO (documented as WPAD/PAC discovery with a fallback to a direct connection, though see transport support below). |
authType: pubnub_proxy_auth_tDefault: PUBNUB_PROXY_AUTH_NONE | Also: PUBNUB_PROXY_AUTH_BASIC (RFC 7617), PUBNUB_PROXY_AUTH_DIGEST (RFC 7616, MD5), or PUBNUB_PROXY_AUTH_NTLM (NTLMv2, ASCII-only credentials). See transport support below. |
hostType: const char*Default: NULL | May be NULL only when type is PUBNUB_PROXY_NONE. Same borrow/deep-copy rule as other string fields. |
portType: uint16_tDefault: 0 | For example, 3128 for HTTP CONNECT, 1080 for SOCKS5. |
usernameType: const char*Default: NULL | May be NULL only when auth is PUBNUB_PROXY_AUTH_NONE. Same borrow/deep-copy rule. |
passwordType: const char*Default: NULL | May be NULL only when auth is PUBNUB_PROXY_AUTH_NONE. Same borrow/deep-copy rule. |
Each transport provider decides whether and how it honors a given proxy type. An unsupported type may be rejected at init time or at request time. Support is transport-dependent. The table above documents the pubnub_proxy_config_t options, not what any one transport actually does with each value.
Support on the default curl transport (the hosted default, per cmake/providers.cmake):
| Value | Support on curl |
|---|---|
PUBNUB_PROXY_HTTP_CONNECT | Supported. |
PUBNUB_PROXY_SOCKS5 | Supported. |
PUBNUB_PROXY_AUTO | Not supported. Rejected as a transport error. It does not perform WPAD/PAC discovery and does not fall back to a direct connection, despite the field's doc comment. |
PUBNUB_PROXY_AUTH_BASIC | Supported. |
PUBNUB_PROXY_AUTH_DIGEST | Accepted by the config API but silently ignored. See warning below. |
PUBNUB_PROXY_AUTH_NTLM | Accepted by the config API but silently ignored. See warning below. |
This is transport-specific, not a limit of the proxy field itself: a different transport provider may support more (or less) of this surface. The socket transport's proxy handling isn't documented here; check its source before relying on it.
curl silently drops Digest and NTLM proxy authentication
On the default curl transport, only PUBNUB_PROXY_AUTH_BASIC is wired to send credentials. PUBNUB_PROXY_AUTH_DIGEST and PUBNUB_PROXY_AUTH_NTLM are accepted without error at configuration time, but the transport never sends the username/password for them. The request proceeds unauthenticated and then fails at the proxy. This looks like a bad-credentials problem, not an unsupported-auth-scheme problem. Verify your auth value if a proxied request is failing for no obvious reason.
Sample code
#include <pubnub/client.h>
#include <pubnub/proxy.h>
static void configure_proxy(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.user_id = "my_unique_user_id";
cfg.proxy = (pubnub_proxy_config_t){
.type = PUBNUB_PROXY_HTTP_CONNECT,
.auth = PUBNUB_PROXY_AUTH_BASIC,
.host = "proxy.example.com",
.port = 3128,
.username = "proxy_user",
show all 18 linesThis follows the designated-initializer form shown in proxy.h's own @code block.
No compiled example ships in the SDK
No example program in the SDK exercises a non-default proxy configuration. This snippet is derived from the pubnub_proxy_config_t field definitions and the header's designated-initializer form, not from a compiled example program.
Returns
None. proxy takes effect at context creation/initialization. There is no separate return value.
TCP keepalive
TCP (Transmission Control Protocol) keepalive periodically probes an idle connection so the SDK notices a dead socket instead of waiting indefinitely for a response.
Method(s)
Header: #include <pubnub/tcp_keepalive.h>
Types: pubnub_tcp_keepalive_config_t
| Parameter | Description |
|---|---|
enabledType: uint8_t (0/1) | Keepalive on/off. |
idle_secType: uint32_t | Seconds idle before the first probe. |
interval_secType: uint32_t | Seconds between probes. |
probe_countType: uint32_t | Probes sent before the connection is declared dead. |
Transport providers copy this value at context init time. Mutating the struct afterward on the caller's side has no effect.
Two different defaults
A pubnub_tcp_keepalive_config_t that you zero-initialize yourself is disabled (enabled = 0). The tcp_keepalive value that pubnub_config_defaults() returns is enabled, using the PUBNUB_TCP_KEEPALIVE_CONFIG_INIT macro from pubnub/tcp_keepalive.h, which expands to idle_sec = 60, interval_sec = 20, probe_count = 3. Which one your context gets depends entirely on whether you started from pubnub_config_defaults(). Use PUBNUB_TCP_KEEPALIVE_CONFIG_INIT directly if you want the same enabled defaults without going through pubnub_config_defaults().
Sample code
#include <pubnub/client.h>
static void configure_tcp_keepalive(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
/* cfg.tcp_keepalive is now { enabled=1, idle_sec=60, interval_sec=20, probe_count=3 } */
cfg.tcp_keepalive.idle_sec = 30;
cfg.tcp_keepalive.interval_sec = 10;
cfg.tcp_keepalive.probe_count = 4;
}
Returns
None. tcp_keepalive is applied when the context is created or initialized.
Providers
pubnub_config_t exposes six provider pointer fields: allocator, transport, serialization, platform, crypto_module, and logger. These let you replace the compiled-in memory, networking, JSON, OS, encryption, and logging backends. This section documents the fields and their validation contract, not how to author a provider. A dedicated providers guide will cover implementing a custom vtable.
Method(s)
| Parameter | Compiled-in default when NULL | Mandatory vtable entries if you supply a provider | Missing-entry error |
|---|---|---|---|
allocator | e.g. a stdlib-backed allocator | alloc, free, buf_acquire, buf_release | PUBNUB_ERR_PROVIDER_MISSING |
transport | e.g. a curl-backed transport | send, poll, cancel | PUBNUB_ERR_PROVIDER_MISSING |
serialization | e.g. a cjson-backed serializer | parse, serialize, value_destroy | PUBNUB_ERR_PROVIDER_MISSING |
platform | e.g. a posix-backed platform layer | monotonic_ms, sleep_ms, random_bytes | PUBNUB_ERR_PROVIDER_MISSING |
crypto_module | disabled, no fallback default | n/a (module, not a raw vtable) | not validated the same way |
logger | built-in default logger | none confirmed mandatory | not validated the same way |
Header: #include <pubnub/client.h>
Types: pubnub_allocator_provider_t*, pubnub_transport_provider_t*, pubnub_serialization_provider_t*, pubnub_platform_provider_t*, pubnub_crypto_module_t*, pubnub_logger_provider_t*
Prerequisite: the exact compiled-in backend for each family (which library or RTOS binding is linked in) is a build-time choice. See Environment Setup.
Ownership / lifetime: all six fields are always borrowed, on both pubnub_create and pubnub_init. The caller must keep every supplied provider struct alive for the lifetime of the context. crypto_module in particular documents this explicitly: the caller manages the module's lifetime.
Blocking: provider init()/deinit() callbacks run inline, synchronously, during pubnub_init/pubnub_create and pubnub_deinit/pubnub_destroy respectively. They never run from a background thread, and are never re-entrant with the configuration API. If one provider's init() fails, the SDK rolls back every provider whose init() already succeeded, calling deinit() on each in reverse order.
Sample code
#include <pubnub/client.h>
static void configure_providers(void)
{
pubnub_config_t cfg = pubnub_config_defaults();
cfg.subscribe_key = "demo";
cfg.user_id = "my_unique_user_id";
/* Leave every provider field NULL to use the compiled-in defaults */
cfg.allocator = NULL;
cfg.transport = NULL;
cfg.serialization = NULL;
cfg.platform = NULL;
cfg.crypto_module = NULL; /* payload encryption stays disabled */
cfg.logger = NULL; /* only the built-in default logger runs */
show all 16 linesReturns
pubnub_init/pubnub_create return PUBNUB_ERR_PROVIDER_MISSING if a non-NULL provider struct you supply is missing one of its mandatory vtable entries. logger isn't validated the same way. A malformed logger vtable is accepted rather than rejected.
Runtime updates
Six pubnub_config_t fields have dedicated runtime setters: user_id, auth_token, origin, log_level, and dns_primary/dns_secondary, which you change together as a pair through one setter. Every other field is fixed once the context is created or initialized. Two more runtime controls aren't tied to a config-struct field at all: pubnub_set_tls_ca_bundle() and pubnub_set_tls_verify() reconfigure the transport's TLS behavior directly.
Method(s)
#include <pubnub/client.h>
pubnub_res_t pubnub_set_user_id(pubnub_context_t* ctx, const char* user_id);
const char* pubnub_get_user_id(const pubnub_context_t* ctx);
pubnub_res_t pubnub_set_auth_token(pubnub_context_t* ctx, const char* token);
const char* pubnub_get_auth_token(const pubnub_context_t* ctx);
pubnub_res_t pubnub_set_origin(pubnub_context_t* ctx, const char* origin);
const char* pubnub_get_origin(const pubnub_context_t* ctx);
pubnub_res_t pubnub_set_log_level(pubnub_context_t* ctx, unsigned int level);
pubnub_res_t pubnub_set_dns_servers(pubnub_context_t* ctx,
const char* primary,
show all 19 lines| Parameter | Description |
|---|---|
pubnub_set_user_id | ctx borrowed. user_id required, non-empty, borrowed. Returns PUBNUB_OK, or PUBNUB_ERR_INVALID_ARGUMENT if NULL/"". |
pubnub_get_user_id | ctx borrowed. Returns the context-owned current user_id, or NULL if ctx is uninitialized. Do not free the returned pointer. It is valid until the next pubnub_set_user_id call or context destruction. |
pubnub_set_auth_token | ctx borrowed. token optional, borrowed, or NULL to clear. Returns PUBNUB_OK. |
pubnub_get_auth_token | ctx borrowed. Returns the context-owned current auth_token, or NULL if unset or ctx is uninitialized. Same non-owning rule as pubnub_get_user_id. |
pubnub_set_origin | ctx borrowed. origin optional, borrowed; a new hostname, or NULL/"" to reset to the compile-time default. Takes effect on the next request dispatch; in-flight requests keep their own copy of the host. Returns PUBNUB_OK, PUBNUB_ERR_NOT_INITIALIZED if ctx is NULL or not initialized, or PUBNUB_ERR_INVALID_ARGUMENT if origin exceeds PUBNUB_CFG_MAX_HOSTNAME_LEN. |
pubnub_get_origin | ctx borrowed. Returns the context-owned current origin, or NULL if ctx is NULL or uninitialized. Valid until the next pubnub_set_origin call or context destruction. |
pubnub_set_log_level | ctx borrowed. level a PUBNUB_LOG_LEVEL_* constant. Returns PUBNUB_OK. |
pubnub_set_dns_servers | ctx borrowed. primary/secondary each an IPv4 or IPv6 address string, or NULL. NULL for primary clears both and reverts to system discovery. Returns PUBNUB_OK, PUBNUB_ERR_INVALID_ARGUMENT if a non-NULL address string doesn't parse, or PUBNUB_ERR_NOT_SUPPORTED if the active transport can't honor custom DNS servers. |
pubnub_set_tls_ca_bundle | ctx borrowed. ca_pem a PEM certificate chain, or NULL to revert to the platform's system trust store. Takes effect on connections opened after the call. In-flight connections are unaffected. Returns PUBNUB_OK. |
pubnub_set_tls_verify | ctx borrowed. skip_verify non-zero to disable peer certificate verification, zero to re-enable it. Returns PUBNUB_OK. |
Header: #include <pubnub/client.h>
Ownership / lifetime: on a pubnub_create-based context, pubnub_set_user_id/pubnub_set_auth_token/pubnub_set_dns_servers deep-copy the new value, mirroring the config-level rule. pubnub_set_origin always copies its argument into an internal fixed-size buffer, regardless of lifecycle. On a pubnub_init-based context, the other setters borrow their value instead. On an arena/bump-pointer allocator target, each call allocates new storage without reclaiming the prior allocation. Minimize how often you rotate these values on memory-constrained targets.
Thread / callback context: these are plain synchronous mutators, not callbacks, so there is no re-entrancy contract to document. pubnub_set_dns_servers() is safe to call from any thread, including on multi-core RTOS targets. A rotation is visible to the middleware pipeline on the very next request, on both the borrowed and deep-copied paths. No pipeline rebuild is required.
Blocking: synchronous, no I/O.
Disabling TLS verification exposes connections to man-in-the-middle attacks
Only call pubnub_set_tls_verify(ctx, 1) in development and testing. Never ship it enabled in production.
Sample code
#include <pubnub/client.h>
static void rotate_credentials(pubnub_context_t* ctx)
{
pubnub_res_t res = pubnub_set_user_id(ctx, "new_user_id");
if (res != PUBNUB_OK) {
/* user_id was NULL or empty */
}
const char* current_user_id = pubnub_get_user_id(ctx);
(void)current_user_id;
res = pubnub_set_auth_token(ctx, "new-auth-token");
if (res != PUBNUB_OK) {
/* handle error */
show all 29 linesReturns
pubnub_set_user_id, pubnub_set_origin, pubnub_set_log_level, pubnub_set_dns_servers, pubnub_set_tls_ca_bundle, and pubnub_set_tls_verify all return pubnub_res_t. pubnub_get_user_id/pubnub_get_auth_token/pubnub_get_origin return a context-owned const char*. For the full log-level catalog and custom logger interface, see Logging.
Driving the event loop
Method(s)
#include <pubnub/client.h>
pubnub_res_t pubnub_process(pubnub_context_t* ctx);
Header: #include <pubnub/client.h>
Prerequisite: ctx must already be initialized (pubnub_init/pubnub_create succeeded).
Blocking: non-blocking. pubnub_process performs a single tick of work and returns immediately.
| Parameter | Direction | Description |
|---|---|---|
ctx | in, borrowed | NULL, never-initialized, or already-deinitialized contexts return PUBNUB_ERR_NOT_INITIALIZED. |
Sample code
#include <pubnub/client.h>
static void drive_event_loop(pubnub_context_t* ctx)
{
pubnub_res_t res;
do {
res = pubnub_process(ctx);
} while (res == PUBNUB_IN_PROGRESS);
}
Returns
| Value | Meaning |
|---|---|
PUBNUB_OK | The context is quiescent. No pending work remains. |
PUBNUB_IN_PROGRESS | Work remains. Call pubnub_process again, or use pubnub_await/pubnub_async instead of polling. |
PUBNUB_ERR_NOT_INITIALIZED | ctx is NULL, was never initialized, or was already deinitialized. |
pubnub_process is one of three ways to consume a pubnub_future_t returned by a feature call. The other two are blocking (pubnub_await) and callback-driven (pubnub_async). These are three consumption styles for the same asynchronous model, not three different builds.
Accessing the serialization provider
Method(s)
#include <pubnub/client.h>
pubnub_serialization_provider_t* pubnub_serialization(pubnub_context_t* ctx);
Header: #include <pubnub/client.h>
Types: pubnub_serialization_provider_t
Ownership / lifetime: the returned pointer is borrowed and stays valid until the context is destroyed or deinitialized. Do not free it. Some vtable entries on the returned provider may themselves be NULL. Check before calling through them.
| Parameter | Direction | Description |
|---|---|---|
ctx | in, borrowed | Returns NULL if ctx is NULL or uninitialized. |
Sample code
#include <pubnub/client.h>
static void inspect_serialization(pubnub_context_t* ctx)
{
pubnub_serialization_provider_t* serialization = pubnub_serialization(ctx);
if (serialization != NULL) {
/* inspect or use the active serialization vtable */
}
}
Returns
The active pubnub_serialization_provider_t* for ctx: either the one you supplied through cfg.serialization, or the compiled-in default. Returns NULL if ctx is NULL or uninitialized.
Embedded and no-heap targets
Three symbols govern how pubnub_config_t and context lifecycle behave on memory-constrained targets:
PUBNUB_CFG_NO_HEAP. A compile-time flag. When1,pubnub_create()andpubnub_destroy()are removed from the compiled API entirely, and onlypubnub_init()/pubnub_deinit()on caller-provided memory remain. TheembeddedCMake profile forces this flag on.fullandminimalforce it off. See Environment Setup for the full profile comparison.pubnub_context_size(). A runtime function that returns the exact number of bytespubnub_initneeds at the memory you provide. Always checksizeof(your_buffer) >= pubnub_context_size()before callingpubnub_init, as shown in Initialization.PUBNUB_CONTEXT_SIZE. A compile-time upper-bound macro for cases where the buffer size must be known at compile time, such asstaticor global storage. It is generated as part of the build and may differ from the exact valuepubnub_context_size()reports at runtime. Always guard with the runtime check even when sizing a buffer with this macro.PUBNUB_ALIGNAS(type). A portability macro frompubnub/pubnub_compat.hthat you must apply to any statically or globally declared context buffer (for example,PUBNUB_ALIGNAS(max_align_t) uint8_t buf[PUBNUB_CONTEXT_SIZE]). Without it, the buffer's natural alignment (1for auint8_t[]) is incompatible withpubnub_context_t, and the cast in(pubnub_context_t*)bufis undefined behavior. This has been observed to fault on strictly-aligned targets such as Cortex-M0.
Compile-time tunables for buffer sizes, request concurrency limits, and the rest of the PUBNUB_CFG_* family are set through CMake, not through pubnub_config_t. See Environment Setup for the full tunable reference and build profiles.