penguin/tinyproxy

An L4 proxy designed to act as a tiny transparent shim

commit 74aeadffb7b0c8d0aaed58f5b678ca0d4a7631c2

author斟酌 鵬兄 <tgckpg@gmail.com>
date2026-05-30T00:15:06Z
subjectSplit event_cb
commit 74aeadffb7b0c8d0aaed58f5b678ca0d4a7631c2
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2026-05-30T00:15:06Z

    Split event_cb
---
 src/stream_builtin.c |  6 ++--
 src/stream_conn.c    | 87 +++++++++++++++++++++++++++++++++++++---------------
 src/stream_conn.h    |  4 ++-
 src/stream_pipe.c    |  2 +-
 src/tinyproxy.c      |  2 +-
 5 files changed, 71 insertions(+), 30 deletions(-)

diff --git a/src/stream_builtin.c b/src/stream_builtin.c
index c1511dd..3713783 100644
--- a/src/stream_builtin.c
+++ b/src/stream_builtin.c
@@ -104,7 +104,7 @@ int start_stream_builtin(conn_t *conn)
 	case X_BUILTIN_ACTION_CLOSE:
 		if (res.data_len > 0) {
 			bufferevent_write(conn->client, res.data, res.data_len);
-			bufferevent_setcb(conn->client, NULL, builtin_close_after_write_cb, event_cb, conn);
+			bufferevent_setcb(conn->client, NULL, builtin_close_after_write_cb, stream_client_event_cb, conn);
 			bufferevent_enable(conn->client, EV_WRITE);
 		} else {
 			free_conn(conn);
@@ -112,12 +112,12 @@ int start_stream_builtin(conn_t *conn)
 		return 0;
 
 	case X_BUILTIN_ACTION_DISCARD:
-		bufferevent_setcb(conn->client, builtin_client_read_cb, NULL, event_cb, conn);
+		bufferevent_setcb(conn->client, builtin_client_read_cb, NULL, stream_client_event_cb, conn);
 		bufferevent_enable(conn->client, EV_READ);
 		return 0;
 
 	case X_BUILTIN_ACTION_HANG:
-		bufferevent_setcb(conn->client, NULL, NULL, event_cb, conn);
+		bufferevent_setcb(conn->client, NULL, NULL, stream_client_event_cb, conn);
 		bufferevent_enable(conn->client, EV_READ);
 		return 0;
 
diff --git a/src/stream_conn.c b/src/stream_conn.c
index 6c89588..78d9328 100644
--- a/src/stream_conn.c
+++ b/src/stream_conn.c
@@ -98,9 +98,57 @@ static void drain_client_then_close(conn_t *conn)
 	}
 }
 
-void event_cb(struct bufferevent *bev, short events, void *arg)
+void stream_client_event_cb(struct bufferevent *bev, short events, void *arg)
 {
+	(void)bev;
+
 	conn_t *conn = arg;
+	const struct route *r = conn->route;
+
+	if (events & BEV_EVENT_TIMEOUT) {
+		LOG_WARN("client connection timed out",
+				"listen", _LOGV_ENDPOINT(&r->listen),
+				"upstream", _LOGV_ENDPOINT(&r->upstream)
+				);
+		free_conn(conn);
+		return;
+	}
+
+	if (events & BEV_EVENT_ERROR) {
+		int err = EVUTIL_SOCKET_ERROR();
+
+		if (conn->close_after_client_eof && err == ECONNRESET) {
+			LOG_INFO("client reset after response drain",
+				"listen", _LOGV_ENDPOINT(&r->listen),
+				"upstream", _LOGV_ENDPOINT(&r->upstream)
+			);
+			free_conn(conn);
+			return;
+		}
+
+		LOG_ERROR("client connection error",
+			"err", _LOGV(evutil_socket_error_to_string(err)),
+			"listen", _LOGV_ENDPOINT(&r->listen),
+			"upstream", _LOGV_ENDPOINT(&r->upstream)
+		);
+
+		free_conn(conn);
+		return;
+	}
+
+	if (events & BEV_EVENT_EOF) {
+		free_conn(conn);
+		return;
+	}
+}
+
+void stream_upstream_event_cb(struct bufferevent *bev, short events, void *arg)
+{
+	(void)bev;
+
+	conn_t *conn = arg;
+
+	const struct route *r = conn->route;
 
 	if (events & BEV_EVENT_CONNECTED) {
 		set_idle_timeouts(conn, conn->route);
@@ -111,7 +159,10 @@ void event_cb(struct bufferevent *bev, short events, void *arg)
 	}
 
 	if (events & BEV_EVENT_TIMEOUT) {
-		LOG_WARN("connection timed out");
+		LOG_WARN("upstream connection timed out",
+				"listen", _LOGV_ENDPOINT(&r->listen),
+				"upstream", _LOGV_ENDPOINT(&r->upstream)
+				);
 		free_conn(conn);
 		return;
 	}
@@ -119,20 +170,7 @@ void event_cb(struct bufferevent *bev, short events, void *arg)
 	if (events & BEV_EVENT_ERROR) {
 		int err = EVUTIL_SOCKET_ERROR();
 
-		if (bev == conn->client &&
-			conn->close_after_client_eof &&
-			err == ECONNRESET) {
-			LOG_INFO("client reset after response drain");
-			free_conn(conn);
-			return;
-		}
-
-		LOG_ERROR("connection error",
-			"err", _LOGV(evutil_socket_error_to_string(err))
-		);
-
-		if (bev == conn->upstream && client_has_pending_output(conn)) {
-			const struct route *r = conn->route;
+		if (client_has_pending_output(conn)) {
 
 			LOG_WARN("upstream error after response queued; draining client",
 				"err", _LOGV(evutil_socket_error_to_string(err)),
@@ -146,17 +184,18 @@ void event_cb(struct bufferevent *bev, short events, void *arg)
 			return;
 		}
 
+		LOG_ERROR("upstream connection error",
+			"err", _LOGV(evutil_socket_error_to_string(err)),
+			"listen", _LOGV_ENDPOINT(&r->listen),
+			"upstream", _LOGV_ENDPOINT(&r->upstream)
+		);
+
 		free_conn(conn);
 		return;
 	}
 
 	if (events & BEV_EVENT_EOF) {
-		if (bev == conn->client && conn->close_after_client_eof) {
-			free_conn(conn);
-			return;
-		}
-
-		if (bev == conn->upstream && client_has_pending_output(conn)) {
+		if (client_has_pending_output(conn)) {
 			drain_client_then_close(conn);
 			return;
 		}
@@ -274,8 +313,8 @@ static void worker_adopt_client_fd(struct worker *w, struct accepted_client *ac)
 	bufferevent_setwatermark(conn->client, EV_READ, 0, BEV_READ_HIGH_WATER);
 	bufferevent_setwatermark(conn->upstream, EV_READ, 0, BEV_READ_HIGH_WATER);
 
-	bufferevent_setcb(conn->client, pipe_client_read_cb, pipe_client_write_cb, event_cb, conn);
-	bufferevent_setcb(conn->upstream, pipe_upstream_read_cb, pipe_upstream_write_cb, event_cb, conn);
+	bufferevent_setcb(conn->client, pipe_client_read_cb, pipe_client_write_cb, stream_client_event_cb, conn);
+	bufferevent_setcb(conn->upstream, pipe_upstream_read_cb, pipe_upstream_write_cb, stream_upstream_event_cb, conn);
 
 	/*
 	 * Do not read from the client yet.
diff --git a/src/stream_conn.h b/src/stream_conn.h
index 4465ff4..bbac010 100644
--- a/src/stream_conn.h
+++ b/src/stream_conn.h
@@ -7,7 +7,9 @@ void dispatch_client_fd(struct worker *w, struct accepted_client *ac);
 void free_conn(conn_t *conn);
 
 void set_client_idle_timeout(conn_t *conn, const struct route *r);
-void event_cb(struct bufferevent *bev, short events, void *arg);
+
+void stream_client_event_cb(struct bufferevent *bev, short events, void *arg);
+void stream_upstream_event_cb(struct bufferevent *bev, short events, void *arg);
 
 #ifdef FUZZ
 int stream_route_adopt_client_for_fuzz(
diff --git a/src/stream_pipe.c b/src/stream_pipe.c
index 7f4b5f5..fc90233 100644
--- a/src/stream_pipe.c
+++ b/src/stream_pipe.c
@@ -116,7 +116,7 @@ void pipe_client_write_cb(struct bufferevent *client, void *arg)
 	);
 
 	if (conn->close_client_after_drain && output_len == 0) {
-		LOG_INFO("client output drained; shutting down write side",
+		LOG_DEBUG("client output drained; shutting down write side",
 			"line", _LOGV(conn->route->line_no)
 		);
 
diff --git a/src/tinyproxy.c b/src/tinyproxy.c
index d95ffe3..b11e00f 100644
--- a/src/tinyproxy.c
+++ b/src/tinyproxy.c
@@ -112,7 +112,7 @@ int main(int argc, char **argv)
 				return 0;
 
 			case 'v':
-				fprintf(stdout, "tinyproxy v0.1.3\n");
+				fprintf(stdout, "tinyproxy v0.1.4\n");
 				free(inline_routes);
 				return 0;