11#if DETWS_ENABLE_NTRIP_CASTER
20 return (c >=
'A' && c <=
'Z') ? (char)(c -
'A' +
'a') : c;
24bool ci_prefix(
const char *s,
const char *end,
const char *prefix)
28 if (s >= end || lower(*s) != lower(*prefix))
37const char *skip_ws(
const char *s,
const char *end)
39 while (s < end && (*s ==
' ' || *s ==
'\t'))
45void fmt_deg2(
char *out,
size_t cap,
double v)
47 int hundredths = (int)(v * 100.0 + (v >= 0.0 ? 0.5 : -0.5));
48 int whole = hundredths / 100;
49 int frac = hundredths % 100;
52 const char *sign = (v < 0.0 && whole == 0) ?
"-" :
"";
53 snprintf(out, cap,
"%s%d.%02d", sign, whole, frac);
58bool find_header_end(
const char *buf,
size_t len,
size_t *hend)
60 for (
size_t i = 0; i < len; i++)
62 if (i + 3 < len && buf[i] ==
'\r' && buf[i + 1] ==
'\n' && buf[i + 2] ==
'\r' && buf[i + 3] ==
'\n')
67 if (i + 1 < len && buf[i] ==
'\n' && buf[i + 1] ==
'\n')
77void scan_headers(
const char *buf,
const char *end, NtripRequest *out)
79 const char *line = buf;
82 const char *le = line;
83 while (le < end && *le !=
'\n')
85 const char *lend = le;
86 if (lend > line && *(lend - 1) ==
'\r')
89 if (ci_prefix(line, lend,
"ntrip-version:"))
91 const char *v = line + 14;
92 while (v + 2 < lend && !(v[0] ==
'2' && v[1] ==
'.' && v[2] ==
'0'))
95 out->version = NtripVersion::NTRIP_V2;
97 else if (ci_prefix(line, lend,
"authorization:"))
99 const char *v = skip_ws(line + 14, lend);
100 if (ci_prefix(v, lend,
"basic "))
102 v = skip_ws(v + 6, lend);
104 out->auth_b64_len = (uint16_t)(lend - v);
112bool ntrip_request_parse(
const char *buf,
size_t len, NtripRequest *out)
114 memset(out, 0,
sizeof(*out));
115 out->version = NtripVersion::NTRIP_V1;
119 if (!find_header_end(buf, len, &hend))
121 out->complete =
true;
123 const char *end = buf + hend;
127 if (!ci_prefix(p, end,
"GET "))
133 p = skip_ws(p + 4, end);
134 const char *target = p;
135 while (p < end && *p !=
' ' && *p !=
'\r' && *p !=
'\n' && *p !=
'?')
137 size_t tlen = (size_t)(p - target);
139 if (tlen == 0 || (tlen == 1 && target[0] ==
'/'))
141 out->want_sourcetable =
true;
145 const char *mp = target;
152 if (mlen >=
sizeof(out->mountpoint))
153 mlen =
sizeof(out->mountpoint) - 1;
154 memcpy(out->mountpoint, mp, mlen);
155 out->mountpoint[mlen] =
'\0';
159 scan_headers(buf, end, out);
163size_t ntrip_build_stream_response(
char *out,
size_t cap, NtripVersion version)
166 if (version == NtripVersion::NTRIP_V2)
167 n = snprintf(out, cap,
168 "HTTP/1.1 200 OK\r\n"
169 "Ntrip-Version: Ntrip/2.0\r\n"
170 "Server: DetWebServer\r\n"
171 "Content-Type: gnss/data\r\n"
172 "Connection: close\r\n\r\n");
174 n = snprintf(out, cap,
"ICY 200 OK\r\n\r\n");
175 if (n < 0 || (
size_t)n >= cap)
180size_t ntrip_build_error_response(
char *out,
size_t cap, NtripVersion version)
183 if (version == NtripVersion::NTRIP_V2)
184 n = snprintf(out, cap,
"HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\nConnection: close\r\n\r\n");
186 n = snprintf(out, cap,
"ERROR - Bad Request\r\n");
187 if (n < 0 || (
size_t)n >= cap)
192size_t ntrip_build_unauthorized_response(
char *out,
size_t cap, NtripVersion version)
195 if (version == NtripVersion::NTRIP_V2)
196 n = snprintf(out, cap,
197 "HTTP/1.1 401 Unauthorized\r\n"
198 "WWW-Authenticate: Basic realm=\"NTRIP\"\r\n"
199 "Content-Length: 0\r\n"
200 "Connection: close\r\n\r\n");
202 n = snprintf(out, cap,
"ERROR - Bad Password\r\n");
203 if (n < 0 || (
size_t)n >= cap)
208size_t ntrip_build_str_record(
char *out,
size_t cap,
const NtripMount *m)
210 if (!m || !m->mountpoint)
214 fmt_deg2(lat,
sizeof(lat), m->lat_deg);
215 fmt_deg2(lon,
sizeof(lon), m->lon_deg);
216 const char *ident = m->identifier ? m->identifier :
"";
217 const char *fmtd = m->format_details ? m->format_details :
"1005(1)";
218 const char *nav = m->nav_system ? m->nav_system :
"GPS";
219 const char *ctry = m->country ? m->country :
"";
220 const char *gen = m->generator ? m->generator :
"DetWebServer";
223 int n = snprintf(out, cap,
"STR;%s;%s;RTCM 3.3;%s;0;%s;none;%s;%s;%s;%d;0;%s;none;N;N;9600;", m->mountpoint, ident,
224 fmtd, nav, ctry, lat, lon, m->nmea_required ? 1 : 0, gen);
225 if (n < 0 || (
size_t)n >= cap)
230size_t ntrip_build_sourcetable(
char *out,
size_t cap, NtripVersion version,
const NtripMount *mounts,
233 static const char ENDLINE[] =
"ENDSOURCETABLE\r\n";
238 for (
size_t i = 0; i < mount_count; i++)
240 size_t rn = ntrip_build_str_record(rec,
sizeof(rec), &mounts[i]);
245 body_len +=
sizeof(ENDLINE) - 1;
249 if (version == NtripVersion::NTRIP_V2)
250 hn = snprintf(out, cap,
251 "HTTP/1.1 200 OK\r\n"
252 "Ntrip-Version: Ntrip/2.0\r\n"
253 "Server: DetWebServer\r\n"
254 "Content-Type: gnss/sourcetable\r\n"
255 "Content-Length: %u\r\n"
256 "Connection: close\r\n\r\n",
259 hn = snprintf(out, cap,
260 "SOURCETABLE 200 OK\r\n"
261 "Server: DetWebServer\r\n"
262 "Content-Type: text/plain\r\n"
263 "Content-Length: %u\r\n\r\n",
265 if (hn < 0 || (
size_t)hn >= cap)
268 size_t pos = (size_t)hn;
269 for (
size_t i = 0; i < mount_count; i++)
271 size_t rn = ntrip_build_str_record(out + pos, cap - pos, &mounts[i]);
272 if (rn == 0 || pos + rn + 2 >= cap)
278 if (pos + (
sizeof(ENDLINE) - 1) >= cap)
280 memcpy(out + pos, ENDLINE,
sizeof(ENDLINE) - 1);
281 pos +=
sizeof(ENDLINE) - 1;
NTRIP caster protocol codec (DETWS_ENABLE_NTRIP_CASTER) - the pure, host-tested core.