Random Port Generator — C source
Generate one or many random TCP/UDP port numbers across registered, ephemeral, or the full range - optionally unique. Runs entirely in your browser with crypto-grade randomness.
This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.
/*
* random-port-generator — C port: random/dynamic port picker.
*
* Display port of the CosmoDev Random Port Generator tool — same contract as
* cli/random-port-generator/random-port-generator.go (the live Go twin) and
* src/lib/random-port.ts (the canonical TypeScript implementation). The
* default rng draws 32 bits from OpenSSL RAND_bytes (a CSPRNG standing in
* for the TS crypto.getRandomValues default) scaled into [0, 1). Invalid
* custom ranges return -1 instead of throwing.
*/
#include <openssl/rand.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* Named ranges — `Range` in the Go twin; the zero value is Registered,
* matching the Go twin and the TS default (registered ports). */
typedef enum { PORT_REGISTERED, PORT_EPHEMERAL, PORT_ANY, PORT_CUSTOM } port_range_t;
/* PortOptions in the TS lib (count/unique cover random_ports). min/max of 0
* mean unset, falling back to the full-range defaults like
* resolveRange({range:'custom'}) in the TS lib. */
typedef struct {
port_range_t range;
int min; /* custom-range lower bound (PORT_CUSTOM only) */
int max; /* custom-range upper bound (PORT_CUSTOM only) */
int count; /* how many ports (random_ports); < 1 clamps to 1 */
int unique; /* dedupe (random_ports) */
double (*rng)(void); /* injectable random in [0, 1); NULL = CSPRNG */
} port_options_t;
/* --------------------------------------------------------------- ranges --- */
/* resolveRange() in the TS lib. */
static void port_resolve_range(const port_options_t *opts, int *lo, int *hi)
{
switch (opts->range) {
case PORT_ANY:
*lo = 1;
*hi = 65535;
return;
case PORT_EPHEMERAL:
*lo = 49152;
*hi = 65535;
return;
case PORT_CUSTOM:
*lo = opts->min ? opts->min : 1;
*hi = opts->max ? opts->max : 65535;
return;
default: /* PORT_REGISTERED */
*lo = 1024;
*hi = 49151;
return;
}
}
/* assertRange() in the TS lib — the TS throw becomes a 0 verdict. */
static int port_range_ok(int lo, int hi)
{
if (lo < 0 || lo > 65535 || hi > 65535 || lo > hi) {
return 0;
}
return 1;
}
/* ----------------------------------------------------------------- random --- */
/* defaultRng() in the TS lib: 32 CSPRNG bits / 2^32, like the TS
* crypto.getRandomValues(new Uint32Array(1))[0] / 2**32. */
static double default_rng(void)
{
unsigned char buf[4];
uint32_t v;
if (RAND_bytes(buf, sizeof buf) != 1) {
return 0.0; /* only on a broken CSPRNG; keep the tool alive */
}
v = (uint32_t) buf[0] | ((uint32_t) buf[1] << 8) |
((uint32_t) buf[2] << 16) | ((uint32_t) buf[3] << 24);
return v / 4294967296.0;
}
/* randomPort() in the TS lib — Port() in the Go twin. -1 on a bad range. */
static int random_port(const port_options_t *opts)
{
int lo, hi;
double (*rng)(void) = opts->rng ? opts->rng : default_rng;
port_resolve_range(opts, &lo, &hi);
if (!port_range_ok(lo, hi)) {
return -1;
}
return lo + (int) (rng() * (double) (hi - lo + 1));
}
/* randomPorts() in the TS lib — Ports() in the Go twin. Writes up to `cap`
* ports into `out` and returns how many, or -1 on a bad range / no room. */
static int random_ports(const port_options_t *opts, int *out, int cap)
{
int lo, hi, count, capacity, n, i, j, t;
double (*rng)(void) = opts->rng ? opts->rng : default_rng;
int *pool;
port_resolve_range(opts, &lo, &hi);
if (!port_range_ok(lo, hi)) {
return -1;
}
count = opts->count < 1 ? 1 : opts->count;
if (!opts->unique) {
if (count > cap) {
return -1;
}
for (i = 0; i < count; i++) {
out[i] = random_port(opts);
}
return count;
}
/* Fisher-Yates partial shuffle over the range to pick n unique ports. */
capacity = hi - lo + 1;
n = count < capacity ? count : capacity;
if (n > cap) {
return -1;
}
pool = malloc((size_t) capacity * sizeof *pool);
if (!pool) {
return -1;
}
for (i = 0; i < capacity; i++) {
pool[i] = lo + i;
}
for (i = 0; i < n; i++) {
j = i + (int) (rng() * (double) (capacity - i));
t = pool[i];
pool[i] = pool[j];
pool[j] = t;
}
for (i = 0; i < n; i++) {
out[i] = pool[i];
}
free(pool);
return n;
}
/* ------------------------------------------------------------------- main --- */
static double rng_zero(void) { return 0.0; }
static double rng_half(void) { return 0.5; }
static double rng_point_nine(void) { return 0.9; }
static void print_ports(const char *label, const int *ports, int n)
{
int i;
printf("%s = [", label);
for (i = 0; i < n; i++) {
printf("%s%d", i ? " " : "", ports[i]);
}
printf("]\n");
}
int main(void)
{
/* Vectors from src/lib/random-port.test.ts — a fixed rng pins every draw. */
port_options_t o;
int lo, hi, buf[8], n;
o = (port_options_t){ PORT_REGISTERED, 0, 0, 1, 0, rng_zero };
printf("registered+0 = %d\n", random_port(&o)); /* 1024 */
o.range = PORT_ANY;
printf("any+0 = %d\n", random_port(&o)); /* 1 */
o.range = PORT_EPHEMERAL;
printf("ephemeral+0 = %d\n", random_port(&o)); /* 49152 */
o = (port_options_t){ PORT_CUSTOM, 8000, 8000, 1, 0, rng_point_nine };
printf("custom 8000-8000 @0.9 = %d\n", random_port(&o)); /* 8000 */
o = (port_options_t){ PORT_CUSTOM, 0, 0, 1, 0, NULL };
port_resolve_range(&o, &lo, &hi);
printf("resolveRange(custom defaults) = %d..%d\n", lo, hi); /* 1..65535 */
o = (port_options_t){ PORT_REGISTERED, 0, 0, 5, 0, rng_zero };
n = random_ports(&o, buf, 8);
print_ports("count=5 @0", buf, n); /* [1024 x5] */
o = (port_options_t){ PORT_CUSTOM, 1, 10, 3, 1, rng_half };
n = random_ports(&o, buf, 8);
print_ports("unique 3 in 1..10 @0.5", buf, n); /* [6 1 7] */
o = (port_options_t){ PORT_CUSTOM, 1, 3, 5, 1, rng_half };
n = random_ports(&o, buf, 8);
print_ports("unique 5 in 1..3 @0.5", buf, n); /* capped at capacity 3 */
o = (port_options_t){ 0, 0, 0, 1, 0, NULL }; /* zero value = registered */
printf("default rng registered = %d (in 1024..49151)\n", random_port(&o));
o = (port_options_t){ PORT_CUSTOM, 70000, 0, 1, 0, NULL }; /* min above 65535 */
printf("invalid: random_port -> %d\n", random_port(&o)); /* -1 */
o = (port_options_t){ PORT_CUSTOM, 100, 50, 1, 0, NULL }; /* min above max */
printf("invalid: random_ports -> %d\n", random_ports(&o, buf, 8)); /* -1 */
return 0;
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →