Csilk 0.2.1
A lightweight, high-performance C HTTP web framework
Loading...
Searching...
No Matches
internal.h File Reference

Internal framework primitives — crypto, codec, MQ, and dispatch. More...

#include <setjmp.h>
#include <stddef.h>
#include <stdint.h>
#include <uv.h>
#include "csilk/csilk.h"
#include "csilk/test/test.h"
Include dependency graph for internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  csilk_sha1_ctx
 SHA-1 hashing context. More...
 
struct  csilk_sha256_ctx
 SHA-256 hashing context. More...
 
struct  csilk_mq_msg_t
 Internal: A single message in the MQ linked-list queue. Messages are heap-allocated and linked via next. More...
 
struct  csilk_mq_topic_t
 Internal: A topic node in the MQ's linked list of topics. Holds the topic name and its associated middleware + subscriber chain. More...
 
struct  csilk_mq_t
 Internal: The Message Queue instance. More...
 
struct  csilk_mq_ctx_t
 Internal: Per-message MQ context passed to middleware and subscribers. More...
 
struct  csilk_mq_work_ctx_t
 Internal: Context passed to libuv's thread-pool work callback. More...
 

Functions

void csilk_sha1_init (csilk_sha1_ctx *context)
 Initialise a SHA-1 hashing context.
 
void csilk_sha1_update (csilk_sha1_ctx *context, const uint8_t *data, size_t len)
 Feed data into the SHA-1 hashing context.
 
void csilk_sha1_final (csilk_sha1_ctx *context, uint8_t digest[20])
 Finalise the SHA-1 hash and write the 20-byte digest.
 
void csilk_sha256_init (csilk_sha256_ctx *context)
 Initialise a SHA-256 hashing context.
 
void csilk_sha256_update (csilk_sha256_ctx *context, const uint8_t *data, size_t len)
 Feed data into the SHA-256 hashing context.
 
void csilk_sha256_final (csilk_sha256_ctx *context, uint8_t digest[32])
 Finalise the SHA-256 hash and write the 32-byte digest.
 
void csilk_hmac_sha256 (const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t out[32])
 Compute HMAC-SHA256 (keyed-hash message authentication code).
 
void csilk_base64_encode (const uint8_t *src, size_t len, char *out)
 Encode raw bytes as a standard Base64 string.
 
void csilk_base64url_encode (const uint8_t *src, size_t len, char *out)
 Encode raw bytes as a Base64URL (RFC 4648 §5) string.
 
int csilk_base64url_decode (const char *src, uint8_t *out)
 Decode a Base64URL (RFC 4648 §5) string to raw bytes.
 
void csilk_ws_parse_frame (csilk_ctx_t *c, const uint8_t *buf, size_t nread)
 Parse an incoming WebSocket frame from the raw TCP stream.
 
void _csilk_send_response (csilk_ctx_t *c) __attribute__((weak))
 Internal: Trigger the response send path.
 
void _csilk_send_data (csilk_ctx_t *c, const uint8_t *data, size_t len)
 Internal: Send data through the appropriate I/O path.
 
void _csilk_hmac_sha256 (csilk_ctx_t *c, const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t out[32])
 Internal: Compute HMAC-SHA256 using the server's crypto driver (if set) or the built-in software implementation.
 
void _csilk_generate_uuid (csilk_ctx_t *c, char buf[37])
 Internal: Generate a random UUID v4 string using the crypto driver (if set) or the built-in /dev/urandom-based implementation.
 
void * _csilk_get_internal_client (csilk_ctx_t *c)
 Get the internal client connection object.
 
void _csilk_set_internal_client (csilk_ctx_t *c, void *client)
 Set the internal client connection object.
 
int _csilk_symmetric_encrypt (csilk_ctx_t *c, const uint8_t *key, size_t key_len, const uint8_t *plaintext, size_t plaintext_len, const uint8_t *iv, size_t iv_len, uint8_t *ciphertext, size_t *ciphertext_len, uint8_t *tag, size_t tag_len)
 Internal: Symmetric encrypt using the context's cipher driver or the built-in OpenSSL AES-256-GCM implementation.
 
int _csilk_symmetric_decrypt (csilk_ctx_t *c, const uint8_t *key, size_t key_len, const uint8_t *ciphertext, size_t ciphertext_len, const uint8_t *iv, size_t iv_len, const uint8_t *tag, size_t tag_len, uint8_t *plaintext, size_t *plaintext_len)
 Internal: Symmetric decrypt using the context's cipher driver or the built-in OpenSSL AES-256-GCM implementation.
 
int _csilk_generate_keypair (csilk_ctx_t *c, char *public_key, size_t *pub_len, char *private_key, size_t *priv_len)
 Internal: Generate an RSA-2048 key pair using the context's cipher driver or the built-in OpenSSL implementation.
 
int _csilk_asymmetric_encrypt (csilk_ctx_t *c, const char *public_key, size_t pub_len, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext, size_t *ciphertext_len)
 Internal: Asymmetric encrypt using the context's cipher driver or the built-in OpenSSL RSA-OAEP implementation.
 
int _csilk_asymmetric_decrypt (csilk_ctx_t *c, const char *private_key, size_t priv_len, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t *plaintext_len)
 Internal: Asymmetric decrypt using the context's cipher driver or the built-in OpenSSL RSA-OAEP implementation.
 
int _csilk_sign (csilk_ctx_t *c, const char *private_key, size_t priv_len, const uint8_t *data, size_t data_len, uint8_t *signature, size_t *sig_len)
 Internal: Sign data using the context's cipher driver or the built-in OpenSSL RSA-PSS implementation.
 
int _csilk_verify (csilk_ctx_t *c, const char *public_key, size_t pub_len, const uint8_t *data, size_t data_len, const uint8_t *signature, size_t sig_len)
 Internal: Verify a signature using the context's cipher driver or the built-in OpenSSL RSA-PSS implementation.
 
size_t csilk_url_decode (char *str)
 URL-decode a percent-encoded string in-place.
 
void csilk_generate_uuid (char *buf)
 Generate a random UUID v4 string (standalone, no context needed).
 
csilk_mq_t * _csilk_mq_new (uv_loop_t *loop)
 Internal: Create a new MQ instance bound to a libuv loop.
 
void _csilk_mq_free (csilk_mq_t *mq)
 Internal: Destroy an MQ instance and release all resources.
 

Detailed Description

Internal framework primitives — crypto, codec, MQ, and dispatch.

This header exposes functions and types used internally by the csilk framework. They are NOT part of the public API and may change without notice. External consumers should not rely on them.

Contents

  • Hashing: SHA-1 (WebSocket handshake), SHA-256, HMAC-SHA256.
  • Encoding: Base64, Base64URL, URL percent-decoding.
  • WebSocket: Frame parsing and dispatch for RFC 6455.
  • Message Queue: In-process pub/sub with WAL persistence, threading via libuv async handles and mutexes.
  • Crypto dispatch: Weak-symbol stubs (_csilk_send_response, _csilk_symmetric_encrypt, etc.) that route through the server's crypto/cipher driver if one is installed, or fall back to built-in software implementations.

Data Structure Documentation

◆ csilk_sha1_ctx

struct csilk_sha1_ctx

SHA-1 hashing context.

Holds intermediate state and buffered data during a multi-step SHA-1 computation. Use csilk_sha1_init / _update / _final.

Note
SHA-1 is considered cryptographically weak for security purposes. It is used internally only for WebSocket handshake compliance (RFC 6455). Do not use for security-critical hashing.
Data Fields
uint8_t buffer[64]

512-bit block buffer for data not yet processed.

uint32_t count[2]

Total message length in bits (64-bit, split into two 32-bit halves).

uint32_t state[5]

160-bit intermediate hash state (5 × 32-bit words).

◆ csilk_sha256_ctx

struct csilk_sha256_ctx

SHA-256 hashing context.

Holds intermediate state and buffered data during a multi-step SHA-256 computation. Use csilk_sha256_init / _update / _final.

Data Fields
uint8_t buffer[64]

512-bit block buffer for data not yet processed.

uint64_t count

Total message length in bits.

uint32_t state[8]

256-bit intermediate hash state (8 × 32-bit words).

◆ csilk_mq_msg_t

struct csilk_mq_msg_t

Internal: A single message in the MQ linked-list queue. Messages are heap-allocated and linked via next.

Data Fields
size_t len

Byte length of payload.

struct csilk_mq_msg_s * next

Pointer to the next message in the queue (NULL for tail).

void * payload

Message payload bytes (heap-allocated copy of published data).

char * topic

NUL-terminated topic string (heap-allocated copy).

◆ csilk_mq_topic_t

struct csilk_mq_topic_t

Internal: A topic node in the MQ's linked list of topics. Holds the topic name and its associated middleware + subscriber chain.

Data Fields
size_t handler_capacity

Allocated capacity of handlers.

size_t handler_count

Number of handlers currently registered.

csilk_mq_handler_t * handlers

Dynamically-grown array of handler function pointers (middleware + subscribers).

char * name

NUL-terminated topic name (e.g., "user.created").

struct csilk_mq_topic_s * next

Pointer to the next topic in the linked list.

◆ csilk_mq_s

struct csilk_mq_s

Internal: The Message Queue instance.

Opaque Message Queue (event bus) instance.

Manages the message queue, topic registry, global middleware, and optional WAL persistence. Publishes are thread-safe (guarded by queue_mutex) and are delivered asynchronously on the main event loop via a uv_async_t handle.

Lifecycle

  1. Created by _csilk_mq_new(loop).
  2. Topics are registered lazily on first subscribe/publish.
  3. Each publish enqueues a message (copied), signals the async handle, and optionally appends to the WAL.
  4. On the main loop, mq_dispatch processes the queue: global middleware runs first, then topic middleware, then subscribers.
  5. Destroyed by _csilk_mq_free() — drains the queue and frees all resources.

Not intended for direct manipulation by user code.

Provides an in-process pub/sub system built on libuv async handles. Thread-safe publishing allows worker threads to send messages to the main event loop. The full lifecycle is:

  1. Retrieve via csilk_server_get_mq (created lazily).
  2. Register middleware (csilk_mq_use) and subscribers (csilk_mq_subscribe).
  3. Publish from any thread (csilk_mq_publish — payload is copied).
  4. Optionally enable WAL persistence (csilk_mq_set_persistence).
  5. Destroyed automatically when the server is freed.

Supports middleware chains, persistence via WAL, and background offloading to libuv's thread pool.

Provides an in-process pub/sub system built on libuv async handles. Thread-safe publishing allows worker threads to send messages to the main event loop. Supports middleware chains, persistence via WAL, and background offloading.

Collaboration diagram for csilk_mq_t:
Data Fields
uv_async_t async_handle

libuv async handle for bridging worker-thread publishes into the main loop.

uint64_t delivered_total

Total messages delivered.

uint64_t failed_total

Total messages failed.

csilk_mq_handler_t * global_middlewares

Array of global middleware (intercepts every topic).

size_t global_mw_capacity

Allocated capacity of global_middlewares.

size_t global_mw_count

Number of global middleware handlers registered.

size_t monitor_capacity

Monitor array capacity.

size_t monitor_count

Number of monitors.

uv_mutex_t monitor_mutex

Protects monitor array.

csilk_ctx_t ** monitors

WebSocket monitor connections.

uint64_t published_total

Total messages published.

uint32_t queue_depth

Current messages in memory.

csilk_mq_msg_t * queue_head

Head of the pending-message linked list.

uv_mutex_t queue_mutex

Mutex guarding the message linked list.

csilk_mq_msg_t * queue_tail

Tail of the pending-message linked list.

csilk_mq_topic_t * topics

Linked list of registered topics.

uv_file wal_fd

File descriptor for the Write-Ahead Log, or -1 if disabled.

uv_mutex_t wal_mutex

Mutex guarding WAL append operations.

char * wal_path

Path to the WAL file (heap-allocated copy, NULL if disabled).

◆ csilk_mq_ctx_s

struct csilk_mq_ctx_s

Internal: Per-message MQ context passed to middleware and subscribers.

Opaque Message Queue context.

Contains the resolved handler chain for the current topic and tracks the current position in the chain.

Created per-message and passed to middleware and subscriber handlers. Provides access to the topic, payload, and chain-control functions. Valid only during the handler invocation — do not store the pointer.

Collaboration diagram for csilk_mq_ctx_t:
Data Fields
int aborted

Non-zero if csilk_mq_abort was called.

size_t handler_count

Total number of handlers in handlers.

int handler_index

Index of the next handler to invoke.

csilk_mq_handler_t * handlers

Combined handler array (global mw + topic mw + subscribers).

csilk_mq_t * mq

Owning MQ instance.

csilk_mq_msg_t * msg

The message being processed.

◆ csilk_mq_work_ctx_t

struct csilk_mq_work_ctx_t

Internal: Context passed to libuv's thread-pool work callback.

Carries the topic, payload, and worker function pointer for background message offloading.

Data Fields
csilk_mq_worker_t handler

User-provided worker function.

size_t len

Byte length of payload.

void * payload

Payload data (heap-allocated copy).

uv_work_t req

libuv work request (must be first for casting).

char * topic

Topic string (heap-allocated copy).

Function Documentation

◆ _csilk_asymmetric_decrypt()

int _csilk_asymmetric_decrypt ( csilk_ctx_t *  c,
const char *  private_key,
size_t  priv_len,
const uint8_t *  ciphertext,
size_t  ciphertext_len,
uint8_t *  plaintext,
size_t *  plaintext_len 
)

Internal: Asymmetric decrypt using the context's cipher driver or the built-in OpenSSL RSA-OAEP implementation.

Parameters
cRequest context (for driver lookup, may be NULL).
private_keyPEM-encoded RSA private key.
priv_lenPrivate key length.
ciphertextData to decrypt (typically 256 bytes for RSA-2048).
ciphertext_lenCiphertext length.
[out]plaintextOutput buffer.
[in,out]plaintext_lenIn: capacity, Out: actual length.
Returns
0 on success, -1 on failure.

◆ _csilk_asymmetric_encrypt()

int _csilk_asymmetric_encrypt ( csilk_ctx_t *  c,
const char *  public_key,
size_t  pub_len,
const uint8_t *  plaintext,
size_t  plaintext_len,
uint8_t *  ciphertext,
size_t *  ciphertext_len 
)

Internal: Asymmetric encrypt using the context's cipher driver or the built-in OpenSSL RSA-OAEP implementation.

Parameters
cRequest context (for driver lookup, may be NULL).
public_keyPEM-encoded RSA public key.
pub_lenPublic key length.
plaintextData to encrypt (max ~190 bytes for RSA-2048).
plaintext_lenPlaintext length.
[out]ciphertext256-byte output buffer.
[in,out]ciphertext_lenIn: capacity, Out: actual length.
Returns
0 on success, -1 on failure.

◆ _csilk_generate_keypair()

int _csilk_generate_keypair ( csilk_ctx_t *  c,
char *  public_key,
size_t *  pub_len,
char *  private_key,
size_t *  priv_len 
)

Internal: Generate an RSA-2048 key pair using the context's cipher driver or the built-in OpenSSL implementation.

Keys are output as PEM-encoded strings.

Parameters
cRequest context (for driver lookup, may be NULL).
[out]public_keyPEM public key buffer.
[in,out]pub_lenIn: capacity, Out: actual PEM length (incl. NUL).
[out]private_keyPEM private key buffer.
[in,out]priv_lenIn: capacity, Out: actual PEM length (incl. NUL).
Returns
0 on success, -1 on failure.

◆ _csilk_generate_uuid()

void _csilk_generate_uuid ( csilk_ctx_t *  c,
char  buf[37] 
)

Internal: Generate a random UUID v4 string using the crypto driver (if set) or the built-in /dev/urandom-based implementation.

Parameters
cRequest context (for driver lookup).
[out]bufOutput buffer of at least 37 bytes. Receives a NUL-terminated UUID string (e.g., "f81d4fae-7dec-11d0-a765-00a0c91e6bf6").

Internal: Generate a random UUID v4 string using the crypto driver (if set) or the built-in /dev/urandom-based implementation.

This is the late-bound UUID generator. If the context has a crypto driver with a cryptographically secure generate_uuid method (e.g., reading from a hardware RNG or via OpenSSL), that is used. Otherwise falls back to the built-in csilk_generate_uuid() which reads /dev/urandom.

The delegation pattern ensures callers always get the best available randomness source without explicit driver management.

Parameters
cRequest context (may be NULL — falls back to built-in).
buf[out] 37-byte buffer for the UUID string.

◆ _csilk_get_internal_client()

void * _csilk_get_internal_client ( csilk_ctx_t *  c)

Get the internal client connection object.

Opaque pointer used by protocol implementations (WebSocket, SSE).

Parameters
cRequest context.
Returns
Internal client handle.

Get the internal client connection object.

Parameters
cThe request context.
Returns
Opaque pointer to csilk_client_t.

◆ _csilk_hmac_sha256()

void _csilk_hmac_sha256 ( csilk_ctx_t *  c,
const uint8_t *  key,
size_t  key_len,
const uint8_t *  data,
size_t  data_len,
uint8_t  out[32] 
)

Internal: Compute HMAC-SHA256 using the server's crypto driver (if set) or the built-in software implementation.

Parameters
cRequest context (for driver lookup).
keyHMAC key.
key_lenKey length.
dataInput data.
data_lenInput length.
[out]out32-byte HMAC output.

Internal: Compute HMAC-SHA256 using the server's crypto driver (if set) or the built-in software implementation.

This is the "late-bound" version of csilk_hmac_sha256(). It checks whether the request context has a crypto driver installed (e.g., OpenSSL, mbedTLS, or a hardware security module). If so, the driver's accelerated HMAC is used. Otherwise, the built-in software implementation serves as the portable fallback.

This pattern allows the application to use pluggable crypto backends without changing caller code. The default built-in implementation is always available for environments without hardware crypto.

Parameters
cRequest context (may be NULL — falls back to built-in).
keyHMAC key.
key_lenKey length.
dataInput data.
data_lenData length.
out[out] 32-byte HMAC output buffer.

◆ _csilk_mq_free()

void _csilk_mq_free ( csilk_mq_t *  mq)

Internal: Destroy an MQ instance and release all resources.

Drains the message queue, frees topics, handlers, and the WAL file.

Parameters
mqThe MQ instance to free.

Internal: Destroy an MQ instance and release all resources.

Triggers uv_close() on the async handle if it is not already closing. The actual cleanup (mutexes, WAL, queue, topics) happens in on_mq_close() when the close callback fires.

Parameters
mqThe MQ instance to free (may be NULL).
Note
This is an async operation — the MQ is not freed immediately. Safe to call with NULL.

◆ _csilk_mq_new()

csilk_mq_t * _csilk_mq_new ( uv_loop_t *  loop)

Internal: Create a new MQ instance bound to a libuv loop.

Parameters
loopThe libuv event loop.
Returns
A new MQ instance (heap-allocated), or NULL on failure.

◆ _csilk_send_data()

void _csilk_send_data ( csilk_ctx_t *  c,
const uint8_t *  data,
size_t  len 
)

Internal: Send data through the appropriate I/O path.

Routes data through the TLS wrapper if TLS is enabled, or writes directly to the TCP socket otherwise.

Parameters
cRequest context.
dataBytes to send.
lenNumber of bytes to send.

◆ _csilk_send_response()

void _csilk_send_response ( csilk_ctx_t *  c)

Internal: Trigger the response send path.

Weak symbol so that tests or custom builds can override it. Called when an async handler finishes and the response should be flushed.

Parameters
cRequest context.

Internal: Trigger the response send path.

This is the central response-serialization function. It constructs the HTTP response bytes in memory and sends them via _csilk_send_data(). The response format is:

HTTP/1.1 <status> <reason>\r
[Transfer-Encoding: chunked\r
] Content-Length: <len>\r
Connection: keep-alive|close\r
<custom headers...>\r
\r
<body>

Response mode selection:

  • Normal (Sync): Content-Length is set to body_len; body is appended inline after the header block.
  • Chunked (Async): No Content-Length; Transfer-Encoding: chunked is set. Used when the handler calls csilk_next() with is_async = true, meaning it may write response chunks over time.
  • File (sendfile): Content-Length is set to file_size; the header is sent via _csilk_send_data, then on_write triggers uv_fs_sendfile for zero-copy file delivery. Only available on non-TLS connections.
  • WebSocket (101): Minimal header; the caller manages frames via csilk_ws_send(). See is_websocket branch.

After the response is sent:

  • For sendfile: return early, defer cleanup to on_sendfile_complete.
  • For keep-alive: restart the idle timer, begin reading next request.
  • For close: initiate uv_close.
  • Fire CSILK_HOOK_REQUEST_END, clean up context.
Parameters
cRequest context (must have _internal_client set).

◆ _csilk_set_internal_client()

void _csilk_set_internal_client ( csilk_ctx_t *  c,
void *  client 
)

Set the internal client connection object.

Parameters
cRequest context.
clientPointer to csilk_client_t (or mock marker).

Set the internal client connection object.

Parameters
cThe request context.
clientOpaque pointer to csilk_client_t.

◆ _csilk_sign()

int _csilk_sign ( csilk_ctx_t *  c,
const char *  private_key,
size_t  priv_len,
const uint8_t *  data,
size_t  data_len,
uint8_t *  signature,
size_t *  sig_len 
)

Internal: Sign data using the context's cipher driver or the built-in OpenSSL RSA-PSS implementation.

Parameters
cRequest context (for driver lookup, may be NULL).
private_keyPEM-encoded RSA private key.
priv_lenPrivate key length.
dataData to sign.
data_lenData length.
[out]signature256-byte signature buffer.
[in,out]sig_lenIn: capacity, Out: actual signature length.
Returns
0 on success, -1 on failure.

◆ _csilk_symmetric_decrypt()

int _csilk_symmetric_decrypt ( csilk_ctx_t *  c,
const uint8_t *  key,
size_t  key_len,
const uint8_t *  ciphertext,
size_t  ciphertext_len,
const uint8_t *  iv,
size_t  iv_len,
const uint8_t *  tag,
size_t  tag_len,
uint8_t *  plaintext,
size_t *  plaintext_len 
)

Internal: Symmetric decrypt using the context's cipher driver or the built-in OpenSSL AES-256-GCM implementation.

Parameters
cRequest context (for driver lookup, may be NULL).
keyDecryption key (must be 32 bytes for AES-256).
key_lenKey length.
ciphertextData to decrypt.
ciphertext_lenCiphertext length.
iv12-byte initialisation vector (nonce).
iv_lenIV length (must be 12 for GCM).
tag16-byte authentication tag.
tag_lenTag length (must be 16).
[out]plaintextOutput buffer (must be at least ciphertext_len bytes).
[in,out]plaintext_lenIn: capacity, Out: actual plaintext length.
Returns
0 on success, -1 on failure (including tag mismatch).

◆ _csilk_symmetric_encrypt()

int _csilk_symmetric_encrypt ( csilk_ctx_t *  c,
const uint8_t *  key,
size_t  key_len,
const uint8_t *  plaintext,
size_t  plaintext_len,
const uint8_t *  iv,
size_t  iv_len,
uint8_t *  ciphertext,
size_t *  ciphertext_len,
uint8_t *  tag,
size_t  tag_len 
)

Internal: Symmetric encrypt using the context's cipher driver or the built-in OpenSSL AES-256-GCM implementation.

Parameters
cRequest context (for driver lookup, may be NULL).
keyEncryption key (must be 32 bytes for AES-256).
key_lenKey length.
plaintextData to encrypt.
plaintext_lenPlaintext length.
iv12-byte initialisation vector (nonce).
iv_lenIV length (must be 12 for GCM).
[out]ciphertextOutput buffer (must be at least plaintext_len bytes).
[in,out]ciphertext_lenIn: capacity, Out: actual ciphertext length.
[out]tag16-byte authentication tag buffer.
tag_lenTag buffer size (must be 16).
Returns
0 on success, -1 on failure.

◆ _csilk_verify()

int _csilk_verify ( csilk_ctx_t *  c,
const char *  public_key,
size_t  pub_len,
const uint8_t *  data,
size_t  data_len,
const uint8_t *  signature,
size_t  sig_len 
)

Internal: Verify a signature using the context's cipher driver or the built-in OpenSSL RSA-PSS implementation.

Parameters
cRequest context (for driver lookup, may be NULL).
public_keyPEM-encoded RSA public key.
pub_lenPublic key length.
dataOriginal signed data.
data_lenData length.
signatureSignature to verify.
sig_lenSignature length.
Returns
0 on valid signature, -1 on invalid or error.

◆ csilk_base64_encode()

void csilk_base64_encode ( const uint8_t *  src,
size_t  len,
char *  out 
)

Encode raw bytes as a standard Base64 string.

Produces a NUL-terminated Base64 string per RFC 4648 §4.

Parameters
srcSource byte buffer.
lenByte length of src.
[out]outOutput buffer. Must be at least ((len + 2) / 3) * 4 + 1 bytes to hold the encoded output plus NUL terminator.

Encode raw bytes as a standard Base64 string.

Processes input in 3-byte groups, producing 4 Base64 characters each. Padding with '=' is added if the input length is not a multiple of 3. The output string is null-terminated.

Parameters
srcInput byte buffer.
lenInput length in bytes.
out[out] Output buffer (must be large enough: 4 * ceil(len/3) + 1).
Note
The caller must ensure out has sufficient capacity. The worst-case output length is ((len + 2) / 3) * 4 + 1.

◆ csilk_base64url_decode()

int csilk_base64url_decode ( const char *  src,
uint8_t *  out 
)

Decode a Base64URL (RFC 4648 §5) string to raw bytes.

Handles both padded and unpadded input.

Parameters
srcNUL-terminated Base64URL string.
[out]outOutput buffer for decoded bytes (must be at least strlen(src) * 3 / 4 bytes).
Returns
The number of decoded bytes on success, or -1 if the input contains invalid characters or the length is invalid.

Decode a Base64URL (RFC 4648 §5) string to raw bytes.

The decoding process is the inverse of Base64URL encoding:

  1. Replace URL-safe characters ('-', '_') with standard Base64 chars ('+', '/').
  2. Restore padding '=' characters so the length is a multiple of 4.
  3. Decode the resulting standard Base64 using a reverse lookup table.

The reverse lookup maps each Base64 character (A-Z, a-z, 0-9, +, /) back to its 6-bit value. Characters outside this set (including whitespace) cause an immediate error return (-1). The '=' padding character terminates decoding early.

Parameters
srcBase64URL-encoded input string (null-terminated).
out[out] Output buffer for decoded bytes.
Returns
The number of decoded bytes on success, or -1 on invalid input (non-Base64 characters) or allocation failure.
Note
The caller should ensure out is large enough (at least strlen(src) * 3 / 4 + 1 bytes).

◆ csilk_base64url_encode()

void csilk_base64url_encode ( const uint8_t *  src,
size_t  len,
char *  out 
)

Encode raw bytes as a Base64URL (RFC 4648 §5) string.

Like Base64 but uses '-' and '_' instead of '+' and '/', and omits padding '=' characters.

Parameters
srcSource byte buffer.
lenByte length of src.
[out]outOutput buffer (must be large enough for the encoded string).

Encode raw bytes as a Base64URL (RFC 4648 §5) string.

Base64URL is the same as standard Base64 but replaces: '+' → '-' (URL-safe, as '+' is treated as space in URL query strings) '/' → '_' (URL-safe, as '/' has path separator meaning) '=' → '' (omitted — padding is unnecessary because length is inferred)

The output is produced by first encoding with standard Base64, then character-substituting and stripping padding.

Parameters
srcInput byte buffer.
lenInput length in bytes.
out[out] Output buffer (must be large enough for the padded Base64 result + 1).
Note
The output is NOT padded with '='. The length can be inferred from strlen(out).

◆ csilk_generate_uuid()

void csilk_generate_uuid ( char *  buf)

Generate a random UUID v4 string (standalone, no context needed).

Uses /dev/urandom or an equivalent OS entropy source.

Parameters
[out]bufOutput buffer of at least 37 bytes. Populated with a NUL-terminated UUID string.

Generate a random UUID v4 string (standalone, no context needed).

UUID v4 (RFC 4122 §4.4) uses random or pseudo-random bytes for all 128 bits, with specific bits reserved for the version and variant:

Field Bits Purpose time_low 32 Random time_mid 16 Random time_hi_ver 16 Version (4 bits) + random (12 bits) clock_seq_hi 8 Variant (2 bits) + random (6 bits) clock_seq_low 8 Random node 48 Random

Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx where '4' indicates RFC 4122 version 4 (random UUID). where 'y' has the top 2 bits set to '10' (RFC 4122 variant).

Reads 16 random bytes from /dev/urandom. If /dev/urandom is unavailable, falls back to rand() (which is NOT cryptographically secure). Sets the UUID version nibble (4) and variant bits (10xx) per RFC 4122.

Parameters
buf[out] 37-byte buffer to receive the UUID string (36 hex chars + 4 hyphens + null terminator).
Note
The output format is: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
Warning
The fallback to rand() is NOT cryptographically secure. On systems without /dev/urandom, CSILK_CRYPTO_DRIVER should supply randomness.

◆ csilk_hmac_sha256()

void csilk_hmac_sha256 ( const uint8_t *  key,
size_t  key_len,
const uint8_t *  data,
size_t  data_len,
uint8_t  out[32] 
)

Compute HMAC-SHA256 (keyed-hash message authentication code).

Implements RFC 2104 using SHA-256 as the underlying hash function.

Parameters
keySecret key bytes.
key_lenByte length of key.
dataInput data to authenticate.
data_lenByte length of data.
[out]out32-byte buffer receiving the HMAC output.

Compute HMAC-SHA256 (keyed-hash message authentication code).

HMAC (Hash-based Message Authentication Code) provides both data integrity and authenticity via a shared secret. The construction is:

HMAC(K, m) = SHA256((K' XOR opad) || SHA256((K' XOR ipad) || m))

where:

  • K' is the key, hashed with SHA256 if longer than 64 bytes (block size).
  • ipad = 0x36 repeated 64 times (inner padding).
  • opad = 0x5C repeated 64 times (outer padding).
  • || denotes concatenation.

The double-hashing protects against length-extension attacks on the underlying hash function. The ipad/opad XOR ensures that the inner and outer hashes use distinct keys derived from the same secret.

Parameters
keyHMAC secret key.
key_lenKey length in bytes.
dataInput message data.
data_lenMessage length in bytes.
out[out] 32-byte output buffer for the HMAC digest.

◆ csilk_sha1_final()

void csilk_sha1_final ( csilk_sha1_ctx context,
uint8_t  digest[20] 
)

Finalise the SHA-1 hash and write the 20-byte digest.

After this call the context should not be used without re-initialising.

Parameters
contextSHA-1 context.
[out]digest20-byte array receiving the SHA-1 hash.

Finalise the SHA-1 hash and write the 20-byte digest.

Pads the message according to RFC 3174 (SHA-1 specification), appends the 64-bit message length, and outputs the final hash digest. After this call, the context should not be used without re-initialization.

Parameters
contextSHA-1 context with accumulated data.
digest[out] 20-byte buffer to receive the hash digest.

◆ csilk_sha1_init()

void csilk_sha1_init ( csilk_sha1_ctx context)

Initialise a SHA-1 hashing context.

Must be called before the first csilk_sha1_update.

Parameters
contextPointer to an uninitialised csilk_sha1_ctx.

Initialise a SHA-1 hashing context.

Sets the five state words to the SHA-1 initial constants and resets the bit count to zero. Must be called before the first csilk_sha1_update().

Parameters
contextSHA-1 context to initialize (must not be NULL).

◆ csilk_sha1_update()

void csilk_sha1_update ( csilk_sha1_ctx context,
const uint8_t *  data,
size_t  len 
)

Feed data into the SHA-1 hashing context.

Can be called multiple times with arbitrary-length inputs.

Parameters
contextSHA-1 context (initialised).
dataInput bytes.
lenNumber of bytes in data.

Feed data into the SHA-1 hashing context.

Processes the input data in 64-byte blocks, updating the context's state. Partial blocks are buffered until the next call or csilk_sha1_final().

Parameters
contextSHA-1 context (initialized via csilk_sha1_init()).
dataInput data buffer.
lenLength of input data in bytes.
Note
Can be called multiple times with successive data chunks.

◆ csilk_sha256_final()

void csilk_sha256_final ( csilk_sha256_ctx context,
uint8_t  digest[32] 
)

Finalise the SHA-256 hash and write the 32-byte digest.

Parameters
contextSHA-256 context.
[out]digest32-byte array receiving the SHA-256 hash.

Finalise the SHA-256 hash and write the 32-byte digest.

Pads the message according to FIPS 180-4, appends the 64-bit message length, and outputs the final 256-bit (32-byte) hash digest.

Parameters
contextSHA-256 context with accumulated data.
digest[out] 32-byte buffer to receive the hash digest.

◆ csilk_sha256_init()

void csilk_sha256_init ( csilk_sha256_ctx context)

Initialise a SHA-256 hashing context.

Parameters
contextPointer to an uninitialised csilk_sha256_ctx.

Initialise a SHA-256 hashing context.

Sets the eight state words to the SHA-256 initial constants and resets the bit count to zero.

Parameters
contextSHA-256 context to initialize (must not be NULL).

◆ csilk_sha256_update()

void csilk_sha256_update ( csilk_sha256_ctx context,
const uint8_t *  data,
size_t  len 
)

Feed data into the SHA-256 hashing context.

Parameters
contextSHA-256 context (initialised).
dataInput bytes.
lenNumber of bytes in data.

Feed data into the SHA-256 hashing context.

Processes the input data in 64-byte blocks, updating the context's state. Partial blocks are buffered. Tracks the total bit count for final padding.

Parameters
contextSHA-256 context (initialized via csilk_sha256_init()).
dataInput data buffer.
lenLength of input data in bytes.

◆ csilk_url_decode()

size_t csilk_url_decode ( char *  str)

URL-decode a percent-encoded string in-place.

Converts XX sequences to their byte values and '+' to space. The decoded string is always shorter than or equal to the input.

Parameters
strNUL-terminated percent-encoded string (modified in-place).
Returns
The length of the decoded string (may be shorter than strlen of the original).

Replaces XX sequences with the corresponding byte value and '+' with space. The decoding is done in-place so the output is never longer than the input.

Parameters
strNull-terminated string to decode (modified in-place).
Returns
The length of the decoded string (may be shorter than original).
Note
If str contains invalid % sequences (e.g., "%ZZ"), they are left as-is.

◆ csilk_ws_parse_frame()

void csilk_ws_parse_frame ( csilk_ctx_t *  c,
const uint8_t *  buf,
size_t  nread 
)

Parse an incoming WebSocket frame from the raw TCP stream.

Processes one or more frames from the receive buffer, dispatches data frames to the registered on_message callback, and handles control frames (ping/pong/close) internally.

Parameters
cRequest context (WebSocket mode must be active).
bufRaw bytes received from the socket.
nreadNumber of bytes in buf.

Parse an incoming WebSocket frame from the raw TCP stream.

Parses the frame header (FIN, opcode, mask, payload length), extracts the payload, applies client-to-server masking if present, and dispatches based on opcode:

  • Opcode 0x08 (close): auto-responds with a close frame and closes the TCP connection.
  • Other data opcodes: invokes the on_ws_message callback if set.
Parameters
cThe request context.
bufRaw frame data received from the socket.
nreadNumber of bytes available in buf.
Note
Only complete frames should be passed. Partial frames will be silently ignored (insufficient data check returns early).
The payload is heap-allocated, unmasked, and freed after dispatch.