12#if DETWS_ENABLE_NTRIP_CASTER
49CasterRover *rover_by_conn(uint8_t slot)
52 if (s_ctx.rovers[i].active && s_ctx.rovers[i].conn_slot == slot)
53 return &s_ctx.rovers[i];
60 if (!s_ctx.rovers[i].active)
66int mount_index(
const char *name,
int listener_id)
70 if (!s_ctx.mounts[i].active)
72 if (listener_id >= 0 && s_ctx.mounts[i].listener_id != (uint8_t)listener_id)
74 if (strcmp(s_ctx.mounts[i].name, name) == 0)
82size_t mounts_on_listener(uint8_t listener_id, NtripMount *out,
size_t cap)
86 if (s_ctx.mounts[i].active && s_ctx.mounts[i].listener_id == listener_id)
87 out[k++] = s_ctx.mounts[i].cfg;
92void reply_and_close(CasterRover *r,
const char *resp,
size_t len)
94 if (len && det_conn_active(r->conn_slot))
101bool auth_ok(
const NtripRequest *req,
const char *expect)
107 size_t el = strnlen(expect, req->auth_b64_len + 1);
108 if (el != req->auth_b64_len)
110 return memcmp(req->auth_b64, expect, el) == 0;
113void serve_sourcetable(CasterRover *r, NtripVersion version)
118 size_t n = ntrip_build_sourcetable(buf,
sizeof(buf), version, list, nm);
119 reply_and_close(r, buf, n);
123void dispatch(CasterRover *r,
const NtripRequest *req)
128 size_t n = ntrip_build_error_response(buf,
sizeof(buf), req->version);
129 reply_and_close(r, buf, n);
132 if (req->want_sourcetable)
134 serve_sourcetable(r, req->version);
137 int mi = mount_index(req->mountpoint, (
int)det_conn_listener_id(r->conn_slot));
140 serve_sourcetable(r, req->version);
143 if (!auth_ok(req, s_ctx.mounts[mi].auth_b64))
145 size_t n = ntrip_build_unauthorized_response(buf,
sizeof(buf), req->version);
146 reply_and_close(r, buf, n);
149 size_t n = ntrip_build_stream_response(buf,
sizeof(buf), req->version);
150 if (n == 0 || !det_conn_active(r->conn_slot) || !
det_conn_send(r->conn_slot, buf, (u16_t)n))
160void caster_on_accept(uint8_t slot)
162 int idx = rover_find_free();
168 CasterRover *r = &s_ctx.rovers[idx];
170 r->streaming =
false;
176void caster_on_data(uint8_t slot)
178 CasterRover *r = rover_by_conn(slot);
188 while (det_conn_available(slot))
189 if (det_conn_read(slot, sink,
sizeof(sink)) == 0)
194 while (det_conn_available(slot) && r->req_len <
sizeof(r->req) - 1)
196 size_t got = det_conn_read(slot, (uint8_t *)r->req + r->req_len,
sizeof(r->req) - 1 - r->req_len);
199 r->req_len += (uint16_t)got;
202 if (ntrip_request_parse(r->req, r->req_len, &req))
207 if (r->req_len >=
sizeof(r->req) - 1)
210 size_t n = ntrip_build_error_response(buf,
sizeof(buf), NtripVersion::NTRIP_V1);
211 reply_and_close(r, buf, n);
215void caster_on_close(uint8_t slot)
217 CasterRover *r = rover_by_conn(slot);
222const ProtoHandler s_caster_handler = {caster_on_accept, caster_on_data, caster_on_close,
nullptr};
226bool det_ntrip_caster_add_mount(uint8_t listener_id,
const NtripMount *mount,
const char *auth_b64)
228 if (!mount || !mount->mountpoint)
235 if (!s_ctx.mounts[i].active)
242 CasterMount *m = &s_ctx.mounts[idx];
244 m->listener_id = listener_id;
245 memcpy(m->name, mount->mountpoint, nl + 1);
247 m->cfg.mountpoint = m->name;
248 m->auth_b64 = auth_b64;
249 if (!s_ctx.registered)
252 s_ctx.registered =
true;
257int det_ntrip_caster_broadcast(
const char *mountpoint,
const uint8_t *data,
size_t len)
259 if (!mountpoint || !data || len == 0)
261 int mi = mount_index(mountpoint, -1);
267 CasterRover *r = &s_ctx.rovers[i];
268 if (!r->active || !r->streaming || r->mount_idx != mi)
270 if (!det_conn_active(r->conn_slot))
278int det_ntrip_caster_subscriber_count(
const char *mountpoint)
282 int mi = mount_index(mountpoint, -1);
287 if (s_ctx.rovers[i].active && s_ctx.rovers[i].streaming && s_ctx.rovers[i].mount_idx == mi)
292void det_ntrip_caster_reset(
void)
295 s_ctx.mounts[i].active =
false;
297 s_ctx.rovers[i].active =
false;
@ PROTO_NTRIP_CASTER
NTRIP caster (DETWS_ENABLE_NTRIP_CASTER): serves RTCM3 corrections to rovers.
#define DETWS_NTRIP_REQ_MAX
Max NTRIP client request size (bytes) the caster buffers while reading the request headers.
#define DETWS_NTRIP_MAX_ROVERS
Max concurrent rover connections a caster serves corrections to (services/gnss).
#define DETWS_NTRIP_MOUNT_MAX
Max length (incl. NUL) of an NTRIP mountpoint name the caster serves.
#define DETWS_NTRIP_MAX_MOUNTS
Max distinct mountpoints a single caster serves (each = one RTCM stream).
Server-side NTRIP caster listener (DETWS_ENABLE_NTRIP_CASTER): the ConnProto::PROTO_NTRIP_CASTER hand...
Layer 5 (Session) - per-protocol connection handler dispatch table.
void proto_register(ConnProto proto, const ProtoHandler *h)
Register h for protocol proto (replaces any previous handler).
Per-protocol connection event/poll callbacks (Layer 5 dispatch vtable).
bool det_conn_send(uint8_t slot, const void *data, u16_t len)
Send len bytes on connection slot (copies data; TLS-aware).
void det_conn_close(uint8_t slot)
Close connection slot gracefully (tcp_close), aborting if the FIN cannot be queued....
Layer 4 (Transport) - TCP connection pool, ring buffers, and lwIP integration.