Developer SDK

C examples

Install the SDK · View source on GitHub ↗

C peer messages

Installation · Integration · Sockets · Messages

This local Device example discovers real-time peers and exchanges text over subprotocol 4096 using the shared URMS v1 TEXT/ACK format. Its files are main.c, runtime.c, codec.h and Makefile; the Device bootstrap is described in Integration.

Build and check

Use C11 and a native SDK with peer/subprotocol APIs. The defaults use ../../../sdk/cgo/include and ../../../sdk/cgo/build/packages/darwin-arm64 from this directory. Build the adjacent SDK first, or override the two paths as shown below. Run from c/messages:

make self-test
make
./messages-example --self-test
./messages-example --version

--self-test checks the golden vectors and malformed-frame rejection without client credentials or live networking. --version reports the SDK version; bindings with native runtime assets also check that they load. Dependency/build steps may download packages.

For an installed native package, supply its include and library directories:

make SDK_INCLUDE=/absolute/path/to/include SDK_LIBDIR=/absolute/path/to/lib

The CMake build uses the package's urnetwork::sdk target:

cmake -S . -B build -DCMAKE_PREFIX_PATH=/absolute/path/to/sdk-prefix
cmake --build build
./build/messages-example --self-test

The native runtime has POSIX and Windows branches; this example was validated on macOS arm64. On Windows, use the executable/configuration path produced by CMake. C's make self-test checks the shared codec without loading the SDK.

Live two-terminal demo

Provision two distinct top-level clients in the same network through your authenticated backend. Terminal A and terminal B need different scoped JWTs with different client_id claims and different persisted instance UUIDs. Only the backend holds the root JWT; Integration includes the executable allocator.

In terminal A, from this directory, export client A's values and start the receiver:

export URNETWORK_CLIENT_JWT='scoped-client-jwt-from-your-service'
export URNETWORK_INSTANCE_ID='persisted-installation-uuid'
./messages-example self
./messages-example peers
./messages-example watch

self prints this client's ID and exits. peers prints the current peer snapshot; watch remains running, refreshes on SDK peer notifications, and receives TEXT/returns ACK. Peer output includes SDK metadata, disconnected count and the SDK-derived client color. Start terminal B with its own URNETWORK_CLIENT_JWT and URNETWORK_INSTANCE_ID, then use A's discovered client ID:

export URNETWORK_PEER_CLIENT_ID='client-id-discovered-in-terminal-a'
./messages-example send $URNETWORK_PEER_CLIENT_ID hi

The sender queries the selected peer's supported subprotocols before sending and requires 4096. A failed query, enqueue failure or ACK timeout is reported as a failure. A matching application ACK means the receiver parsed and accepted the TEXT; correlation uses (source client ID, message ID). Use the discovered client ID as the destination, not an instance UUID or display name. For text containing spaces, keep the message in one quoted argument (or inside the quoted Maven/Gradle argument string).

Incoming bytes and retained source identity are copied before the native callback returns; queued work parses frames and sends ACKs outside that callback. Keep subscriptions and Device owners alive through shutdown. Some FFI bridges keep a small callback root until process exit because native close can race a late callback. The protocol defines exact validation, UTF-8 limits, golden bytes and timeout semantics.