Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Neumenon/cowrie/llms.txt
Use this file to discover all available pages before exploring further.
C SDK
The C implementation provides a low-level, zero-dependency codec suitable for embedded systems, IoT devices, and performance-critical applications.Installation
Using CMake
cd c
mkdir build && cd build
cmake ..
make
make install
Manual Integration
Copy the header files and source files to your project:cp c/include/*.h your_project/include/
cp c/src/*.c your_project/src/
Basic Usage
Gen1: Lightweight Encoding
#include "cowrie_gen1.h"
// Create a value
cowrie_g1_value_t *obj = cowrie_g1_object(2);
cowrie_g1_object_set(obj, "name", cowrie_g1_string("Alice", 5));
cowrie_g1_object_set(obj, "age", cowrie_g1_int64(30));
// Encode
cowrie_g1_buf_t buf;
cowrie_g1_buf_init(&buf);
int err = cowrie_g1_encode(obj, &buf);
if (err != COWRIE_G1_OK) {
fprintf(stderr, "Encode failed\n");
return -1;
}
// Use buf.data and buf.len
write(fd, buf.data, buf.len);
// Cleanup
cowrie_g1_value_free(obj);
cowrie_g1_buf_free(&buf);
Gen2: Full Codec
#include "cowrie_gen2.h"
// Create value
cowrie_value_t *val = cowrie_object(2);
cowrie_object_set(val, "name", cowrie_string("Alice", 5));
cowrie_object_set(val, "age", cowrie_int64(30));
// Encode
uint8_t *data;
size_t len;
int err = cowrie_encode(val, &data, &len);
if (err != COWRIE_OK) {
fprintf(stderr, "Encode failed\n");
return -1;
}
// Use data
write(fd, data, len);
// Cleanup
free(data);
cowrie_value_free(val);
Type System
Creating Values (Gen1)
// Null
cowrie_g1_value_t *null_val = cowrie_g1_null();
// Boolean
cowrie_g1_value_t *bool_val = cowrie_g1_bool(true);
// Integer
cowrie_g1_value_t *int_val = cowrie_g1_int64(42);
// Float
cowrie_g1_value_t *float_val = cowrie_g1_float64(3.14);
// String (with length)
cowrie_g1_value_t *str_val = cowrie_g1_string("hello", 5);
// Bytes
uint8_t bytes[] = {0x01, 0x02, 0x03};
cowrie_g1_value_t *bytes_val = cowrie_g1_bytes(bytes, 3);
Creating Values (Gen2)
// UUID (16 bytes)
uint8_t uuid_bytes[16] = {0};
cowrie_value_t *uuid = cowrie_uuid128(uuid_bytes);
// Datetime (nanoseconds since epoch)
int64_t nanos = 1234567890123456789LL;
cowrie_value_t *dt = cowrie_datetime64(nanos);
// BigInt
uint8_t bigint_bytes[] = {0x01, 0x23, 0x45};
cowrie_value_t *big = cowrie_bigint(bigint_bytes, 3);
// Decimal128
uint8_t coef[16] = {0};
cowrie_value_t *dec = cowrie_decimal128(2, coef); // scale=2
Reading Values
Gen1
cowrie_g1_value_t *val;
cowrie_g1_decode(data, len, &val);
switch (val->type) {
case COWRIE_G1_TYPE_NULL:
printf("null\n");
break;
case COWRIE_G1_TYPE_BOOL:
printf("bool: %s\n", val->bool_val ? "true" : "false");
break;
case COWRIE_G1_TYPE_INT64:
printf("int64: %lld\n", (long long)val->int64_val);
break;
case COWRIE_G1_TYPE_FLOAT64:
printf("float64: %f\n", val->float64_val);
break;
case COWRIE_G1_TYPE_STRING:
printf("string: %.*s\n",
(int)val->string_val.len,
val->string_val.data);
break;
case COWRIE_G1_TYPE_ARRAY:
printf("array[%zu]\n", val->array_val.len);
for (size_t i = 0; i < val->array_val.len; i++) {
// Process val->array_val.items[i]
}
break;
case COWRIE_G1_TYPE_OBJECT:
printf("object{%zu}\n", val->object_val.len);
for (size_t i = 0; i < val->object_val.len; i++) {
const char *key = val->object_val.members[i].key;
cowrie_g1_value_t *value = val->object_val.members[i].value;
printf(" %s: ", key);
// Process value
}
break;
}
cowrie_g1_value_free(val);
Gen2
cowrie_value_t *val;
cowrie_decode(data, len, &val);
switch (val->type) {
case COWRIE_STRING:
printf("%.*s\n",
(int)val->string_val.len,
val->string_val.data);
break;
case COWRIE_INT64:
printf("%lld\n", (long long)val->int64_val);
break;
case COWRIE_TENSOR:
printf("Tensor<dtype=%d> shape=[",
val->tensor_val.dtype);
for (size_t i = 0; i < val->tensor_val.rank; i++) {
printf("%llu%s",
(unsigned long long)val->tensor_val.dims[i],
i < val->tensor_val.rank - 1 ? ", " : "");
}
printf("]\n");
break;
case COWRIE_ARRAY:
for (size_t i = 0; i < val->array_val.len; i++) {
// Process val->array_val.items[i]
}
break;
case COWRIE_OBJECT:
for (size_t i = 0; i < val->object_val.count; i++) {
const char *key = val->object_val.keys[i];
cowrie_value_t *value = val->object_val.values[i];
printf("%s: ", key);
// Process value
}
break;
}
cowrie_value_free(val);
Memory Management
Manual Memory
// Always free values when done
cowrie_g1_value_t *val = cowrie_g1_string("test", 4);
// ... use val ...
cowrie_g1_value_free(val);
// Free buffers
cowrie_g1_buf_t buf;
cowrie_g1_buf_init(&buf);
// ... use buf ...
cowrie_g1_buf_free(&buf);
Arena Allocator (Gen2)
// Create arena for batch allocations
cowrie_arena_t *arena = cowrie_arena_new(4096); // 4KB
// Allocate values from arena
cowrie_value_t *v1 = cowrie_arena_string(arena, "test1", 5);
cowrie_value_t *v2 = cowrie_arena_string(arena, "test2", 5);
// Free entire arena at once
cowrie_arena_free(arena);
Error Handling
Gen1 Errors
int err = cowrie_g1_decode(data, len, &val);
switch (err) {
case COWRIE_G1_OK:
// Success
break;
case COWRIE_G1_ERR_NOMEM:
fprintf(stderr, "Out of memory\n");
break;
case COWRIE_G1_ERR_INVALID:
fprintf(stderr, "Invalid data\n");
break;
case COWRIE_G1_ERR_EOF:
fprintf(stderr, "Unexpected end of data\n");
break;
case COWRIE_G1_ERR_DEPTH:
fprintf(stderr, "Max nesting depth exceeded\n");
break;
default:
fprintf(stderr, "Unknown error: %d\n", err);
}
Gen2 Errors
int err = cowrie_decode(data, len, &val);
if (err != COWRIE_OK) {
const char *msg = cowrie_error_string(err);
fprintf(stderr, "Decode error: %s\n", msg);
return -1;
}
File I/O
Writing to File
#include "cowrie_gen1.h"
#include <stdio.h>
cowrie_g1_value_t *val = cowrie_g1_object(1);
cowrie_g1_object_set(val, "data", cowrie_g1_string("test", 4));
// Encode
cowrie_g1_buf_t buf;
cowrie_g1_buf_init(&buf);
cowrie_g1_encode(val, &buf);
// Write to file
FILE *f = fopen("output.cowrie", "wb");
fwrite(buf.data, 1, buf.len, f);
fclose(f);
// Cleanup
cowrie_g1_value_free(val);
cowrie_g1_buf_free(&buf);
Reading from File
#include "cowrie_gen1.h"
#include <stdio.h>
#include <stdlib.h>
// Read file
FILE *f = fopen("data.cowrie", "rb");
fseek(f, 0, SEEK_END);
size_t len = ftell(f);
fseek(f, 0, SEEK_SET);
uint8_t *data = malloc(len);
fread(data, 1, len, f);
fclose(f);
// Decode
cowrie_g1_value_t *val;
int err = cowrie_g1_decode(data, len, &val);
if (err == COWRIE_G1_OK) {
// Process val
cowrie_g1_value_free(val);
}
free(data);
Security Options
Gen1 Limits
// Configure security limits (optional)
struct cowrie_g1_limits {
size_t max_depth; // Default: 1000
size_t max_array_len; // Default: 100M
size_t max_object_len; // Default: 10M
size_t max_string_len; // Default: 500MB
size_t max_bytes_len; // Default: 1GB
};
cowrie_g1_limits_t limits = {
.max_depth = 500,
.max_array_len = 1000000,
.max_object_len = 100000,
.max_string_len = 10000000,
.max_bytes_len = 100000000,
};
cowrie_g1_value_t *val;
int err = cowrie_g1_decode_with_limits(data, len, &val, &limits);
Performance Tips
-
Reuse buffers: Initialize once, clear between uses
cowrie_g1_buf_t buf; cowrie_g1_buf_init(&buf); for (int i = 0; i < N; i++) { buf.len = 0; // Reset cowrie_g1_encode(values[i], &buf); // Use buf } cowrie_g1_buf_free(&buf); - Use arena allocators: For batch allocations in Gen2
-
Pre-allocate capacity: Reserve space for known sizes
cowrie_g1_buf_reserve(&buf, 4096); - Avoid copying: Use pointers and references when possible
- Profile your usage: Use tools like valgrind and gprof
Embedded Systems
Static Allocation
// Pre-allocate buffer on stack
uint8_t buffer[1024];
cowrie_g1_buf_t buf = {
.data = buffer,
.len = 0,
.cap = sizeof(buffer),
};
// Encode without heap allocation
cowrie_g1_value_t val = {
.type = COWRIE_G1_TYPE_STRING,
.string_val = {.data = "test", .len = 4},
};
cowrie_g1_encode_static(&val, &buf);
No Standard Library
// Define custom allocators
void* my_malloc(size_t size);
void my_free(void* ptr);
// Override default allocators
cowrie_g1_set_allocator(my_malloc, my_free);
Complete Example
#include "cowrie_gen1.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
// Create data
cowrie_g1_value_t *obj = cowrie_g1_object(3);
cowrie_g1_object_set(obj, "name", cowrie_g1_string("Alice", 5));
cowrie_g1_object_set(obj, "age", cowrie_g1_int64(30));
// Array of scores
double scores[] = {98.5, 87.3, 92.1};
cowrie_g1_object_set(obj, "scores",
cowrie_g1_float64_array(scores, 3));
// Encode
cowrie_g1_buf_t buf;
cowrie_g1_buf_init(&buf);
int err = cowrie_g1_encode(obj, &buf);
if (err != COWRIE_G1_OK) {
fprintf(stderr, "Encode failed: %d\n", err);
return 1;
}
printf("Encoded size: %zu bytes\n", buf.len);
// Decode
cowrie_g1_value_t *decoded;
err = cowrie_g1_decode(buf.data, buf.len, &decoded);
if (err != COWRIE_G1_OK) {
fprintf(stderr, "Decode failed: %d\n", err);
return 1;
}
// Access data
if (decoded->type == COWRIE_G1_TYPE_OBJECT) {
cowrie_g1_value_t *name = cowrie_g1_object_get(decoded, "name");
if (name && name->type == COWRIE_G1_TYPE_STRING) {
printf("Name: %.*s\n",
(int)name->string_val.len,
name->string_val.data);
}
}
// Cleanup
cowrie_g1_value_free(obj);
cowrie_g1_value_free(decoded);
cowrie_g1_buf_free(&buf);
return 0;
}
Compilation
# Compile with optimization
gcc -O3 -o example example.c -lcowrie
# Compile for embedded (no stdlib)
gcc -nostdlib -O2 -o firmware firmware.c cowrie_gen1.c
# Cross-compile for ARM
arm-none-eabi-gcc -mcpu=cortex-m4 -o app.elf app.c -lcowrie