diff --git a/be_misc.c b/be_misc.c index 84d24639..9bd3bdd3 100644 --- a/be_misc.c +++ b/be_misc.c @@ -59,12 +59,15 @@ void backend_socket_log(Seat *seat, LogContext *logctx, } } -void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, size_t len) +void psb_init(ProxyStderrBuf *psb) +{ + psb->size = 0; +} + +void log_proxy_stderr(Plug *plug, ProxyStderrBuf *psb, + const void *vdata, size_t len) { const char *data = (const char *)vdata; - size_t pos = 0; - const char *nlpos; - char *msg, *fullmsg; /* * This helper function allows us to collect the data written to a @@ -72,43 +75,77 @@ void log_proxy_stderr(Plug *plug, bufchain *buf, const void *vdata, size_t len) * happen to get from its pipe, and whenever we have a complete * line, we pass it to plug_log. * - * Prerequisites: a plug to log to, and a bufchain stored - * somewhere to collect the data in. + * (We also do this when the buffer in psb fills up, to avoid just + * allocating more and more memory forever, and also to keep Event + * Log lines reasonably bounded in size.) + * + * Prerequisites: a plug to log to, and a ProxyStderrBuf stored + * somewhere to collect any not-yet-output partial line. */ - while (pos < len && (nlpos = memchr(data+pos, '\n', len-pos)) != NULL) { + while (len > 0) { /* - * Found a newline in the current input buffer. Append it to - * the bufchain (which may contain a partial line from last - * time). + * Copy as much data into psb->buf as will fit. */ - bufchain_add(buf, data + pos, nlpos - (data + pos)); + assert(psb->size < lenof(psb->buf)); + size_t to_consume = lenof(psb->buf) - psb->size; + if (to_consume > len) + to_consume = len; + memcpy(psb->buf + psb->size, data, to_consume); + data += to_consume; + len -= to_consume; + psb->size += to_consume; /* - * Collect the resulting line of data and pass it to plug_log. + * Output any full lines in psb->buf. */ - size_t msglen = bufchain_size(buf); - assert(msglen < ~(size_t)0); - msg = snewn(msglen+1, char); - bufchain_fetch(buf, msg, msglen); - bufchain_consume(buf, msglen); - while (msglen > 0 && (msg[msglen-1] == '\n' || msg[msglen-1] == '\r')) - msglen--; - msg[msglen] = '\0'; - fullmsg = dupprintf("proxy: %s", msg); - plug_log(plug, 2, NULL, 0, fullmsg, 0); - sfree(fullmsg); - sfree(msg); + size_t pos = 0; + while (pos < psb->size) { + char *nlpos = memchr(psb->buf + pos, '\n', psb->size - pos); + if (!nlpos) + break; + + /* + * Found a newline in the buffer, so we can output a line. + */ + size_t endpos = nlpos - psb->buf; + while (endpos > pos && (psb->buf[endpos-1] == '\n' || + psb->buf[endpos-1] == '\r')) + endpos--; + char *msg = dupprintf( + "proxy: %.*s", (int)(endpos - pos), psb->buf + pos); + plug_log(plug, 2, NULL, 0, msg, 0); + sfree(msg); + + pos = nlpos - psb->buf + 1; + assert(pos <= psb->size); + } /* - * Advance past the newline. + * If the buffer is completely full and we didn't output + * anything, then output the whole thing, flagging it as a + * truncated line. + */ + if (pos == 0 && psb->size == lenof(psb->buf)) { + char *msg = dupprintf( + "proxy (partial line): %.*s", (int)psb->size, psb->buf); + plug_log(plug, 2, NULL, 0, msg, 0); + sfree(msg); + + pos = psb->size = 0; + } + + /* + * Now move any remaining data up to the front of the buffer. + */ + size_t newsize = psb->size - pos; + if (newsize) + memmove(psb->buf, psb->buf + pos, newsize); + psb->size = newsize; + + /* + * And loop round again if there's more data to be read from + * our input. */ - pos += nlpos+1 - (data + pos); } - - /* - * Now any remaining data is a partial line, which we save for - * next time. - */ - bufchain_add(buf, data + pos, len - pos); } diff --git a/network.h b/network.h index 387c46f1..84287e72 100644 --- a/network.h +++ b/network.h @@ -290,7 +290,13 @@ void backend_socket_log(Seat *seat, LogContext *logctx, int type, SockAddr *addr, int port, const char *error_msg, int error_code, Conf *conf, bool session_started); + +typedef struct ProxyStderrBuf { + char buf[8192]; + size_t size; +} ProxyStderrBuf; +void psb_init(ProxyStderrBuf *psb); void log_proxy_stderr( - Plug *plug, bufchain *buf, const void *vdata, size_t len); + Plug *plug, ProxyStderrBuf *psb, const void *vdata, size_t len); #endif diff --git a/unix/uxfdsock.c b/unix/uxfdsock.c index 9ac3cdf8..54b29f6c 100644 --- a/unix/uxfdsock.c +++ b/unix/uxfdsock.c @@ -18,7 +18,7 @@ typedef struct FdSocket { bufchain pending_output_data; bufchain pending_input_data; - bufchain pending_input_error_data; + ProxyStderrBuf psb; enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof; int pending_error; @@ -300,7 +300,7 @@ static void fdsocket_select_result_input_error(int fd, int event) retd = read(fd, buf, sizeof(buf)); if (retd > 0) { - log_proxy_stderr(fds->plug, &fds->pending_input_error_data, buf, retd); + log_proxy_stderr(fds->plug, &fds->psb, buf, retd); } else { del234(fdsocket_by_inerrfd, fds); uxsel_del(fds->inerrfd); @@ -337,7 +337,7 @@ Socket *make_fd_socket(int infd, int outfd, int inerrfd, Plug *plug) bufchain_init(&fds->pending_input_data); bufchain_init(&fds->pending_output_data); - bufchain_init(&fds->pending_input_error_data); + psb_init(&fds->psb); if (fds->outfd >= 0) { if (!fdsocket_by_outfd) diff --git a/windows/winhsock.c b/windows/winhsock.c index 4bebba75..5bbcfc2c 100644 --- a/windows/winhsock.c +++ b/windows/winhsock.c @@ -33,8 +33,8 @@ typedef struct HandleSocket { /* We buffer data here if we receive it from winhandl while frozen. */ bufchain inputdata; - /* Data received from stderr_H, if we have one. */ - bufchain stderrdata; + /* Handle logging proxy error messages from stderr_H, if we have one. */ + ProxyStderrBuf psb; bool defer_close, deferred_close; /* in case of re-entrance */ @@ -86,7 +86,7 @@ static size_t handle_stderr( HandleSocket *hs = (HandleSocket *)handle_get_privdata(h); if (!err && len > 0) - log_proxy_stderr(hs->plug, &hs->stderrdata, data, len); + log_proxy_stderr(hs->plug, &hs->psb, data, len); return 0; } @@ -127,7 +127,6 @@ static void sk_handle_close(Socket *s) if (hs->recv_H != hs->send_H) CloseHandle(hs->recv_H); bufchain_clear(&hs->inputdata); - bufchain_clear(&hs->stderrdata); sfree(hs); } @@ -332,7 +331,7 @@ Socket *make_handle_socket(HANDLE send_H, HANDLE recv_H, HANDLE stderr_H, hs->error = NULL; hs->frozen = UNFROZEN; bufchain_init(&hs->inputdata); - bufchain_init(&hs->stderrdata); + psb_init(&hs->psb); hs->recv_H = recv_H; hs->recv_h = handle_input_new(hs->recv_H, handle_gotdata, hs, flags);