ssize_t netstring_get_length(VSTREAM *stream) { const char *myname = "netstring_get_length"; ssize_t len = 0; int ch; for (;;) { switch (ch = VSTREAM_GETC(stream)) { case VSTREAM_EOF: netstring_except(stream, vstream_ftimeout(stream) ? NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); case ':': if (msg_verbose > 1) msg_info("%s: read netstring length %ld", myname, (long) len); return (len); default: if (!ISDIGIT(ch)) netstring_except(stream, NETSTRING_ERR_FORMAT); len = len * 10 + ch - '0'; /* vstream_fread() would read zero bytes. Reject input anyway. */ if (len < 0) netstring_except(stream, NETSTRING_ERR_SIZE); break; } } }
static void read_data(int unused_event, void *context) { SINK_STATE *state = (SINK_STATE *) context; int fd = vstream_fileno(state->stream); int count; /* * Refill the VSTREAM buffer, if necessary. */ if (VSTREAM_GETC(state->stream) == VSTREAM_EOF) netstring_except(state->stream, vstream_ftimeout(state->stream) ? NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); state->count--; /* * Flush the VSTREAM buffer. As documented, vstream_fseek() discards * unread input. */ if ((count = vstream_peek(state->stream)) > 0) { state->count -= count; if (state->count <= 0) { send_reply(state); return; } vstream_fpurge(state->stream, VSTREAM_PURGE_BOTH); } /* * Do not block while waiting for the arrival of more data. */ event_disable_readwrite(fd); event_enable_read(fd, read_data, context); }
VSTRING *netstring_get_data(VSTREAM *stream, VSTRING *buf, ssize_t len) { const char *myname = "netstring_get_data"; /* * Allocate buffer space. */ VSTRING_RESET(buf); VSTRING_SPACE(buf, len); /* * Read the payload and absorb the terminator. */ if (vstream_fread(stream, STR(buf), len) != len) netstring_except(stream, vstream_ftimeout(stream) ? NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); if (msg_verbose > 1) msg_info("%s: read netstring data %.*s", myname, (int) (len < 30 ? len : 30), STR(buf)); netstring_get_terminator(stream); /* * Position the buffer. */ VSTRING_AT_OFFSET(buf, len); return (buf); }
VSTRING *netstring_get(VSTREAM *stream, VSTRING *buf, ssize_t limit) { ssize_t len; len = netstring_get_length(stream); if (limit && len > limit) netstring_except(stream, NETSTRING_ERR_SIZE); netstring_get_data(stream, buf, len); return (buf); }
void netstring_get_terminator(VSTREAM *stream) { if (VSTREAM_GETC(stream) != ',') netstring_except(stream, NETSTRING_ERR_FORMAT); }