Prerequisites. You can read C and know what a UDP socket is. Building requires a C11 compiler, OpenSSL and GLib/GIO development files,
pkg-config, and Make or CMake. Everything else is explained here.
GLib’s main loop drives a request containing a resource rate limit and a pre-work latency guard. Allowed work is measured afterward and reported as one latency sample; denied, cancelled, or failed work produces no sample.
This example attaches non-owning GIOChannel watches for the runtime’s UDP
sockets to a GMainLoop. A one-shot GLib timeout follows the active admission
deadline, so socket readiness and client retries use the same main context.
The rate limit protects a named resource, and the latency guard checks existing service history before protected work begins. Only admitted, successfully completed work is measured and reported.
Build the library from the repository root, then use either build file:
make -C ../..
make
./glib-example
cmake -S . -B build
cmake --build build
./build/glib-example
CMake compiles the client sources with the selected compiler. Native Visual Studio builds therefore do not consume a Unix or MinGW static archive.
RATELIMITLY_AUTH_KEY is required. With no overrides, the runtime decodes the
key ID, derives c-<key-id>.p0.ratelimitly.com, and discovers
_ratelimitly._udp.c-<key-id>.p0.ratelimitly.com.
RATELIMITLY_TENANT optionally replaces that derived tenant DNS name. A fixed
development responder uses RATELIMITLY_EXAMPLE_SERVER_HOST and
RATELIMITLY_EXAMPLE_SERVER_PORT; set both or neither. Leave all three
overrides unset for key-derived P0 discovery.
export RATELIMITLY_AUTH_KEY='rl-aes1...'
# Optional fixed development endpoint; set both or neither.
export RATELIMITLY_EXAMPLE_SERVER_HOST=127.0.0.1
export RATELIMITLY_EXAMPLE_SERVER_PORT=39082
./glib-example
flowchart TD
Start["Start resource + latency admission"] --> Sources["Attach non-owning GIOChannel sources"]
Sources --> Timer["Attach one-shot GLib timeout"]
Timer --> Loop["g_main_loop_run"]
Loop --> Event{"GMainContext callback"}
Event -->|Socket source| Read["Drain runtime datagrams"]
Event -->|Timeout source| Timeout["Advance admission timeout"]
Read --> Decision{"Admission complete?"}
Timeout --> Decision
Decision -->|No| Rearm["Replace deadline source"]
Rearm --> Loop
Decision -->|Denied| Reject["Finish without latency sample"]
Decision -->|Allowed| Work["Run work, measure, report latency"]
The latency guard uses tracker history already at the server and runs before
the protected operation. After both policies allow the request,
r_runtime_admission_run_and_report() measures the synchronous
prepare_response() callback with a monotonic clock and sends one post-work
sample. Denied, cancelled, and failed operations send none.
Synchronous work makes the lifecycle visible, but real service work should not
block a GMainContext. Start asynchronous work after admission, retain request
identity and a monotonic start time, and report once from its successful
completion callback.
GLib/GIO and this source have POSIX and Windows branches. Unix wraps sockets
with g_io_channel_unix_new; Windows calls
g_io_channel_win32_new_socket and links ws2_32 plus dnsapi. Windows
support is conditional: GLib’s constructor accepts a gint, while a native
WinSock SOCKET is pointer-width, and this source’s narrowing cast has not been
proved handle-safe or executed in repository CI. Use libuv, libevent, or the
native Win32 example until that contract is verified for the target build.
Ubuntu CI verifies allow, resource denial, latency denial, and exact
request/report pairing with a synthetic responder. Trusted main runs also
exercise key-derived production P0 discovery and admission; the UDP report has
no application acknowledgement, so this smoke proves its local send path.
The application owns the loop, source IDs, channels, request, and copied outcome. Remove sources and unref non-owning channels before destroying runtime sockets, and keep client transitions on the main-context thread.
| Term | Meaning |
|---|---|
GMainLoop |
GLib object that repeatedly dispatches ready sources from a main context. |
| IOChannel | GLib GIOChannel wrapper used here to watch a socket without taking ownership of it. |
| source | Socket watch or timer registered with a GLib main context. |
| WinSock | Native Windows sockets API. |
SOCKET |
Pointer-width WinSock handle, which is not guaranteed to fit in GLib’s gint parameter. |
| latency guard | Pre-work policy check against existing samples for a service. |
| latency sample | Post-work duration sent after admitted work succeeds. |
| POSIX | Portable Operating System Interface family that defines Unix file-descriptor and socket conventions. |