diff options
| author | David Lamparter <equinox@diac24.net> | 2021-02-18 22:52:23 +0100 |
|---|---|---|
| committer | David Lamparter <equinox@diac24.net> | 2021-03-27 16:56:55 +0100 |
| commit | 212e04e5a7f682594dab26cd8354bc4fa040b61f (patch) | |
| tree | 59a09a812b868332f073985494ee0a61910da9fd /lib/sockunion.c | |
| parent | bcf9d7d8aa77c66ac2e99f75ae11e276accecb1d (diff) | |
lib: rework printfrr extensions to output directly
Allowing printfrr extensions to directly write to the output buffer has
a few advantages:
- there is no arbitrary length limit imposed (previously 64)
- the output doesn't need to be copied another time
- the extension can directly use bprintfrr() to put together pieces
The downside is that the theoretical length (regardless of available
buffer space) must be computed correctly.
Extended unit tests to test these paths a bit more thoroughly.
Signed-off-by: David Lamparter <equinox@diac24.net>
Diffstat (limited to 'lib/sockunion.c')
| -rw-r--r-- | lib/sockunion.c | 71 |
1 files changed, 34 insertions, 37 deletions
diff --git a/lib/sockunion.c b/lib/sockunion.c index d65235b41c..25de8f7dd0 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -664,54 +664,51 @@ void sockunion_init(union sockunion *su) } printfrr_ext_autoreg_p("SU", printfrr_psu) -static ssize_t printfrr_psu(char *buf, size_t bsz, const char *fmt, +static ssize_t printfrr_psu(struct fbuf *buf, const char **fmt, int prec, const void *ptr) { const union sockunion *su = ptr; - struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 }; bool include_port = false; bool endflags = false; - ssize_t consumed = 2; - - if (su) { - while (!endflags) { - switch (fmt[consumed++]) { - case 'p': - include_port = true; - break; - default: - consumed--; - endflags = true; - break; - } - }; - - switch (sockunion_family(su)) { - case AF_UNSPEC: - bprintfrr(&fb, "(unspec)"); - break; - case AF_INET: - inet_ntop(AF_INET, &su->sin.sin_addr, buf, bsz); - fb.pos += strlen(fb.buf); - if (include_port) - bprintfrr(&fb, ":%d", su->sin.sin_port); - break; - case AF_INET6: - inet_ntop(AF_INET6, &su->sin6.sin6_addr, buf, bsz); - fb.pos += strlen(fb.buf); - if (include_port) - bprintfrr(&fb, ":%d", su->sin6.sin6_port); + ssize_t ret = 0; + char cbuf[INET6_ADDRSTRLEN]; + + if (!su) + return bputs(buf, "NULL"); + + while (!endflags) { + switch (**fmt) { + case 'p': + (*fmt)++; + include_port = true; break; default: - bprintfrr(&fb, "(af %d)", sockunion_family(su)); + endflags = true; + break; } + } - fb.pos[0] = '\0'; - } else { - strlcpy(buf, "NULL", bsz); + switch (sockunion_family(su)) { + case AF_UNSPEC: + ret += bputs(buf, "(unspec)"); + break; + case AF_INET: + inet_ntop(AF_INET, &su->sin.sin_addr, cbuf, sizeof(cbuf)); + ret += bputs(buf, cbuf); + if (include_port) + ret += bprintfrr(buf, ":%d", su->sin.sin_port); + break; + case AF_INET6: + inet_ntop(AF_INET6, &su->sin6.sin6_addr, cbuf, sizeof(cbuf)); + ret += bputs(buf, cbuf); + if (include_port) + ret += bprintfrr(buf, ":%d", su->sin6.sin6_port); + break; + default: + ret += bprintfrr(buf, "(af %d)", sockunion_family(su)); } - return consumed; + return ret; } int sockunion_is_null(const union sockunion *su) |
