NetBurner 3.5.8
PDF Version
Toggle main menu visibility
json_writer.h
1
/*NB_REVISION*/
2
3
/*NB_COPYRIGHT*/
4
5
// json_writer.h — accumulate a JSON (or any text) response and flush it to a socket in ONE
6
// write, so it leaves as full-size TCP segments instead of many tiny per-field/per-byte ones.
7
//
8
// Why: handlers that build JSON with repeated fdprintf(sock, ...) produce hundreds/thousands of
9
// 1-2 byte TCP segments. Under concurrent NTP load a single lost tiny segment triggers a ~1 s TCP
10
// retransmit timeout that freezes the shared ethernet TX path (NTP included). Fewer, larger
11
// segments make that far less likely. (The pjs-based handlers use SendJsonBody() in
12
// webfunctions.cpp for the same reason; this is the equivalent for fdprintf-style handlers.)
13
//
14
// Usage:
15
// JsonWriter jw(sock); // grabs a heap buffer (grows as needed)
16
// jw.Printf("{\"a\":%d,", x);
17
// ...
18
// jw.Printf("}");
19
// // flushed automatically when jw goes out of scope (or call jw.Flush()).
20
//
21
// On allocation failure it degrades gracefully to per-call socket writes (never drops output).
22
23
#ifndef NTP1061_JSON_WRITER_H
24
#define NTP1061_JSON_WRITER_H
25
26
#include <stdarg.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <iosys.h>
// writeall
30
31
class
JsonWriter
32
{
33
int
m_sock;
34
char
*m_buf;
35
int
m_cap;
36
int
m_len;
37
38
public
:
39
explicit
JsonWriter(
int
sock,
int
initCap = 2048)
40
: m_sock(sock), m_buf((char *)malloc(initCap)), m_cap(m_buf ? initCap : 0), m_len(0) {}
41
42
~JsonWriter() { Flush();
if
(m_buf) free(m_buf); }
43
44
void
Printf(
const
char
*fmt, ...)
45
{
46
va_list ap;
47
48
// No buffer (allocation failed): write this piece straight to the socket.
49
if
(!m_buf)
50
{
51
char
tmp[256];
52
va_start(ap, fmt);
53
int
n = vsnprintf(tmp,
sizeof
(tmp), fmt, ap);
54
va_end(ap);
55
if
(n > 0)
writeall
(m_sock, tmp, (n < (
int
)
sizeof
(tmp)) ? n : (
int
)
sizeof
(tmp) - 1);
56
return
;
57
}
58
59
for
(;;)
60
{
61
va_start(ap, fmt);
62
int
need = vsnprintf(m_buf + m_len, m_cap - m_len, fmt, ap);
63
va_end(ap);
64
65
if
(need < 0)
return
;
// encoding error
66
if
(m_len + need < m_cap) { m_len += need;
return
; }
// fit
67
68
// Did not fit: grow and retry.
69
int
nc = m_cap * 2;
70
while
(m_len + need + 1 > nc) nc *= 2;
71
char
*nb = (
char
*)realloc(m_buf, nc);
72
if
(!nb)
73
{
74
// Out of memory: flush what we have, then write this piece directly.
75
Flush();
76
char
tmp[256];
77
va_start(ap, fmt);
78
int
n = vsnprintf(tmp,
sizeof
(tmp), fmt, ap);
79
va_end(ap);
80
if
(n > 0)
writeall
(m_sock, tmp, (n < (
int
)
sizeof
(tmp)) ? n : (
int
)
sizeof
(tmp) - 1);
81
return
;
82
}
83
m_buf = nb;
84
m_cap = nc;
85
}
86
}
87
88
void
Flush() {
if
(m_buf && m_len > 0) {
writeall
(m_sock, m_buf, m_len); m_len = 0; } }
89
};
90
91
#endif
// NTP1061_JSON_WRITER_H
writeall
int writeall(int fd, const char *buf, int nbytes=0)
Write the specified number of bytes to a file descriptor. Will block until all bytes are sent,...
examples
PlatformSpecific
NTP1061
src
json_writer.h
Generated by
1.18.0