un-inception/clients/c/examples
russell@unturf.com 00dfc1bebc fix: Rename C SDK files to un.c/un.h to match naming convention
- Renamed src/unsandbox.c -> src/un.c
- Renamed src/unsandbox.h -> src/un.h
- Updated all references in Makefile, README.md, IMPLEMENTATION.md
- Matches un.py, un.js, un.go, etc. naming pattern
2026-01-15 16:50:03 -05:00
..
credentials.c feat: per-client Makefile infrastructure for 4-mode testing 2026-01-15 16:39:56 -05:00
error_handling.c feat: per-client Makefile infrastructure for 4-mode testing 2026-01-15 16:39:56 -05:00
fibonacci.c feat: per-client Makefile infrastructure for 4-mode testing 2026-01-15 16:39:56 -05:00
hello_world.c feat: per-client Makefile infrastructure for 4-mode testing 2026-01-15 16:39:56 -05:00
README.md fix: Rename C SDK files to un.c/un.h to match naming convention 2026-01-15 16:50:03 -05:00

Unsandbox C SDK Examples

This directory contains practical examples demonstrating core functionality of the unsandbox C library.

Examples Overview

1. hello_world.c - Simple Execute Example

A minimal example showing basic setup and execution patterns.

What it demonstrates:

  • Loading credentials from environment variables
  • Preparing code for execution
  • Basic error handling
  • Memory management patterns
  • API structure overview

Topics:

  • UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY environment variables
  • execute_code() function signature
  • Return value handling (malloc'd strings)
  • Safe memory cleanup with free()

Compile:

gcc -o hello_world hello_world.c -I../../.. -lcurl -lwebsockets -lssl -lcrypto

Run:

export UNSANDBOX_PUBLIC_KEY=unsb-pk-xxxxx
export UNSANDBOX_SECRET_KEY=unsb-sk-xxxxx
./hello_world

2. fibonacci.c - Computation Example

Demonstrates executing computational code across multiple programming languages.

What it demonstrates:

  • Same algorithm in Python, JavaScript, Go, and Rust
  • Execution timing with clock_gettime()
  • Multi-language support
  • Timeout handling
  • Error detection patterns

Topics:

  • execute_code() for synchronous execution
  • Language auto-detection from file extensions
  • Measuring execution time
  • Timeout detection and handling
  • Runtime error vs output distinction

Compile:

gcc -o fibonacci fibonacci.c -I../../.. -lcurl -lwebsockets -lssl -lcrypto

Run:

export UNSANDBOX_PUBLIC_KEY=unsb-pk-xxxxx
export UNSANDBOX_SECRET_KEY=unsb-sk-xxxxx
./fibonacci

Code examples included:

  • Python recursive fibonacci
  • JavaScript functional fibonacci
  • Go compiled fibonacci
  • Rust zero-cost abstraction fibonacci

3. error_handling.c - Proper Error Handling Patterns

Comprehensive error handling demonstration with categorized error types.

What it demonstrates:

  • Error classification (auth, rate-limit, timeout, runtime, server)
  • Error type detection from responses
  • Retry strategies with exponential backoff
  • Transient vs permanent errors
  • Error logging patterns

Topics:

  • ErrorType enumeration
  • HTTP error codes (401, 429, 500)
  • Response content parsing
  • Automatic retry logic
  • Timeout detection in output

Compile:

gcc -o error_handling error_handling.c -I../../.. -lcurl -lwebsockets -lssl -lcrypto

Run:

./error_handling

Patterns demonstrated:

  1. NULL check - Detection of memory allocation failures
  2. HTTP error checking - Parsing status codes from responses
  3. Retry logic - Exponential backoff for rate limits
  4. Timeout detection - Identifying killed processes
  5. Error logging - Writing to log files for debugging

Error types:

  • ERROR_INVALID_CREDS - 401 Unauthorized
  • ERROR_RATE_LIMITED - 429 Too Many Requests
  • ERROR_TIMEOUT - Execution exceeded time limit
  • ERROR_RUNTIME_ERROR - Exception in user code
  • ERROR_SERVER_ERROR - 500+ server errors
  • ERROR_NETWORK - Connection failed
  • ERROR_OUT_OF_MEMORY - malloc() failed

4. credentials.c - Credential Loading from 4 Sources

Shows how to load credentials with priority ordering.

What it demonstrates:

  • Credential priority ordering
  • All four credential sources
  • Account selection and management
  • Config file format
  • Security best practices

Topics:

  • CLI flags: -p (public key) and -k (secret key)
  • Environment variables: UNSANDBOX_PUBLIC_KEY, UNSANDBOX_SECRET_KEY
  • Config file: ~/.unsandbox/accounts.csv
  • Account selection: --account N and UNSANDBOX_ACCOUNT=N

Compile:

gcc -o credentials credentials.c -I../../.. -lcurl -lwebsockets -lssl -lcrypto

Run:

./credentials

Credential sources (highest to lowest priority):

  1. CLI Flags

    un -p unsb-pk-xxxxx -k unsb-sk-xxxxx script.py
    
  2. Environment Variables

    export UNSANDBOX_PUBLIC_KEY=unsb-pk-xxxxx
    export UNSANDBOX_SECRET_KEY=unsb-sk-xxxxx
    ./un script.py
    
  3. Config File

    ~/.unsandbox/accounts.csv
    # Format: public_key,secret_key (one per line)
    un --account 0 script.py  # Use first account
    
  4. Fallback (Error)

    Error: API credentials required
    

Setup config file:

mkdir -p ~/.unsandbox
cat > ~/.unsandbox/accounts.csv << 'EOF'
unsb-pk-account1,unsb-sk-account1
unsb-pk-account2,unsb-sk-account2
EOF
chmod 600 ~/.unsandbox/accounts.csv

Common Compilation Patterns

Standard compile (requires un.c)

gcc -o example example.c -I../../.. \
  -lcurl -lwebsockets -lssl -lcrypto

With optimization

gcc -O2 -o example example.c -I../../.. \
  -lcurl -lwebsockets -lssl -lcrypto

With debugging symbols

gcc -g -o example example.c -I../../.. \
  -lcurl -lwebsockets -lssl -lcrypto

With all warnings

gcc -Wall -Wextra -o example example.c -I../../.. \
  -lcurl -lwebsockets -lssl -lcrypto

Dependencies

Required libraries:

apt install build-essential libcurl4-openssl-dev libwebsockets-dev libssl-dev

Key Patterns

Pattern 1: Safe memory allocation

char *result = execute_code(language, code, pk, sk);
if (!result) {
  fprintf(stderr, "Failed to allocate result\n");
  return 1;
}

// Use result...

free(result);  // Always free!

Pattern 2: Error detection

char *result = execute_code(language, code, pk, sk);
if (!result) {
  return 1;
}

if (strstr(result, "error") || strstr(result, "Error")) {
  fprintf(stderr, "Execution error: %s\n", result);
  free(result);
  return 1;
}

printf("Output: %s\n", result);
free(result);

Pattern 3: Retry with backoff

const int MAX_RETRIES = 3;
const int RETRY_DELAY_MS = 1000;

for (int attempt = 0; attempt < MAX_RETRIES; attempt++) {
  char *result = execute_code(language, code, pk, sk);
  if (result) {
    printf("Output: %s\n", result);
    free(result);
    return 0;
  }

  int backoff = RETRY_DELAY_MS * (1 << attempt);
  usleep(backoff * 1000);
}

fprintf(stderr, "Failed after %d attempts\n", MAX_RETRIES);
return 1;

Pattern 4: Async execution

// Start async execution
char *job_id = execute_async(language, code, pk, sk);
if (!job_id) {
  fprintf(stderr, "Failed to start async execution\n");
  return 1;
}

printf("Job ID: %s\n", job_id);

// Poll for completion
sleep(1);  // Wait before checking
char *result = wait_for_job(job_id, pk, sk);
if (result) {
  printf("Result: %s\n", result);
  free(result);
}

free(job_id);

Pattern 5: Timeout handling

struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);

char *result = execute_code(language, code, pk, sk);

clock_gettime(CLOCK_MONOTONIC, &end);
long elapsed_ms = (end.tv_sec - start.tv_sec) * 1000 +
                  (end.tv_nsec - start.tv_nsec) / 1000000;

if (elapsed_ms > 300000) {  // 300 seconds
  fprintf(stderr, "Execution took %ld ms (likely timed out)\n", elapsed_ms);
}

if (result) {
  printf("Output: %s\n", result);
  free(result);
}

API Reference

Synchronous execution

char *execute_code(
  const char *language,
  const char *code,
  const char *public_key,
  const char *secret_key
);

Returns: JSON response string (must be freed by caller) or NULL on failure

Asynchronous execution

char *execute_async(
  const char *language,
  const char *code,
  const char *public_key,
  const char *secret_key
);

Returns: Job ID string (must be freed) or NULL on failure

Get job status

char *get_job(
  const char *job_id,
  const char *public_key,
  const char *secret_key
);

Returns: JSON status (must be freed) or NULL on failure

Wait for completion

char *wait_for_job(
  const char *job_id,
  const char *public_key,
  const char *secret_key
);

Returns: Final result (must be freed) or NULL on failure

Cancel job

char *cancel_job(
  const char *job_id,
  const char *public_key,
  const char *secret_key
);

Returns: Cancellation response (must be freed) or NULL on failure

List jobs

char *list_jobs(
  const char *public_key,
  const char *secret_key
);

Returns: JSON job list (must be freed) or NULL on failure

Get supported languages

char *get_languages(
  const char *public_key,
  const char *secret_key
);

Returns: JSON language list (must be freed) or NULL on failure

Language detection

const char *detect_language(const char *filename);

Returns: Language name (e.g., "python", "javascript") or NULL

Environment Variables

Required for execution

  • UNSANDBOX_PUBLIC_KEY - API public key (unsb-pk-xxxxx)
  • UNSANDBOX_SECRET_KEY - API secret key (unsb-sk-xxxxx)

Optional

  • UNSANDBOX_ACCOUNT - Account index in config file (default: 0)

Configuration File

Location: ~/.unsandbox/accounts.csv

Format:

unsb-pk-account1,unsb-sk-account1
unsb-pk-account2,unsb-sk-account2
unsb-pk-account3,unsb-sk-account3

Permissions: Should be 600 (readable only by owner)

Error Codes

Code HTTP Status Meaning Action
401 Unauthorized Invalid credentials Check API keys
429 Too Many Requests Rate limited Implement backoff
500+ Server Error Server issue Retry later
Timeout N/A Execution time exceeded Optimize code
OOM N/A Out of memory Reduce input size

Memory Management

IMPORTANT: All functions returning char * allocate memory with malloc(). You must free this memory when done:

char *result = execute_code(...);
if (result) {
  // Use result...
  free(result);  // MUST do this!
}

Failure to free will cause memory leaks in long-running applications.

Testing

Compile all examples:

gcc -o hello_world hello_world.c -I../../.. -lcurl -lwebsockets -lssl -lcrypto
gcc -o fibonacci fibonacci.c -I../../.. -lcurl -lwebsockets -lssl -lcrypto
gcc -o error_handling error_handling.c -I../../.. -lcurl -lwebsockets -lssl -lcrypto
gcc -o credentials credentials.c -I../../.. -lcurl -lwebsockets -lssl -lcrypto

Run examples:

export UNSANDBOX_PUBLIC_KEY=unsb-pk-xxxxx
export UNSANDBOX_SECRET_KEY=unsb-sk-xxxxx

./hello_world
./fibonacci
./error_handling
./credentials

Security Notes

  1. Never hardcode credentials - Always use environment variables or config files
  2. Protect config files - Use chmod 600 ~/.unsandbox/accounts.csv
  3. Rotate keys regularly - Old keys should be revoked and removed
  4. Use separate credentials - Dev, staging, and production should have different keys
  5. Don't log secrets - Never print API keys to logs or stdout
  6. Clean shell history - Remove entries with credentials: history -c

Example Workflows

Web server integration

// In request handler
const char *language = "python";
const char *code = user_submitted_code;
const char *pk = getenv("UNSANDBOX_PUBLIC_KEY");
const char *sk = getenv("UNSANDBOX_SECRET_KEY");

char *result = execute_code(language, code, pk, sk);
if (result) {
  send_response(200, result);
  free(result);
} else {
  send_response(500, "Execution failed");
}

Batch processing

// Process many files
for (int i = 0; i < file_count; i++) {
  char *code = read_file(files[i]);
  char *result = execute_code("python", code, pk, sk);

  if (result) {
    printf("File %s: %s\n", files[i], result);
    free(result);
  } else {
    fprintf(stderr, "Failed: %s\n", files[i]);
  }

  free(code);
}

Async job management

// Start job
char *job_id = execute_async("python", code, pk, sk);
if (job_id) {
  // Store job_id in database
  // Later, check status periodically
  char *status = get_job(job_id, pk, sk);
  if (status) {
    printf("Status: %s\n", status);
    free(status);
  }
  free(job_id);
}

Troubleshooting

"API credentials required"

Set environment variables:

export UNSANDBOX_PUBLIC_KEY=unsb-pk-xxxxx
export UNSANDBOX_SECRET_KEY=unsb-sk-xxxxx

"401 Unauthorized"

Check that API keys are correct:

echo $UNSANDBOX_PUBLIC_KEY
echo $UNSANDBOX_SECRET_KEY

"429 Rate limited"

Implement exponential backoff in retry logic (see error_handling.c)

Memory leaks

Use valgrind to check:

valgrind --leak-check=full ./example

Compilation errors

Ensure dependencies are installed:

apt install libcurl4-openssl-dev libwebsockets-dev libssl-dev

Further Reading

  • See ../Makefile for compilation and testing infrastructure
  • See ../tests/test_library.c for unit test patterns
  • See ../../un.c for full library implementation
  • Visit https://un.com for API documentation