Update.
This commit is contained in:
parent
dd30b5d18d
commit
43fcdc4e26
90
rproxy.c
90
rproxy.c
@ -1706,12 +1706,34 @@ void close_connection(int fd) {
|
||||
// Prevent double-closing
|
||||
if (conn->fd == -1) return;
|
||||
|
||||
int pair_fd = -1;
|
||||
if (conn->pair && conn->pair->fd != -1) {
|
||||
pair_fd = conn->pair->fd;
|
||||
conn->pair->pair = NULL;
|
||||
connection_t *pair = conn->pair;
|
||||
|
||||
// --- START: ROBUST STATE & PAIR MANAGEMENT FIX ---
|
||||
|
||||
// Decouple the pair immediately to prevent circular logic.
|
||||
if (pair) {
|
||||
pair->pair = NULL;
|
||||
}
|
||||
|
||||
// If the connection being closed is a CLIENT, we must also close its upstream pair.
|
||||
if (conn->type == CONN_TYPE_CLIENT && pair) {
|
||||
close_connection(pair->fd);
|
||||
}
|
||||
|
||||
// If the connection being closed is an UPSTREAM, its client pair must be
|
||||
// reset to handle the next keep-alive request. This is the core of the fix.
|
||||
if (conn->type == CONN_TYPE_UPSTREAM && pair && pair->type == CONN_TYPE_CLIENT) {
|
||||
log_info("[STATE-FIX] Upstream fd=%d closed. Resetting client fd=%d for next request.", fd, pair->fd);
|
||||
pair->state = CLIENT_STATE_READING_HEADERS;
|
||||
|
||||
// A new request might have been read into the buffer due to the race condition.
|
||||
// We must attempt to process it now to serve it correctly.
|
||||
if (buffer_available_read(&pair->read_buf) > 0) {
|
||||
handle_client_read(pair);
|
||||
}
|
||||
}
|
||||
// --- END: ROBUST STATE & PAIR MANAGEMENT FIX ---
|
||||
|
||||
// Record request end if needed
|
||||
if (conn->vhost_stats && conn->request_start_time > 0) {
|
||||
monitor_record_request_end(conn->vhost_stats, conn->request_start_time);
|
||||
@ -1726,7 +1748,7 @@ void close_connection(int fd) {
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("Closing connection on fd %d, pair %d, remaining: %d", fd, pair_fd, monitor.active_connections);
|
||||
log_debug("Closing connection on fd %d, remaining: %d", fd, monitor.active_connections);
|
||||
|
||||
// Remove from epoll before closing
|
||||
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
|
||||
@ -1749,13 +1771,11 @@ void close_connection(int fd) {
|
||||
memset(conn, 0, sizeof(connection_t));
|
||||
conn->type = CONN_TYPE_UNUSED;
|
||||
conn->fd = -1;
|
||||
|
||||
// Close the paired connection
|
||||
if (pair_fd != -1) {
|
||||
close_connection(pair_fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void connect_to_upstream(connection_t *client, const char *data, size_t data_len) {
|
||||
if (!client || !data) return;
|
||||
|
||||
@ -2110,15 +2130,16 @@ static void handle_forwarding(connection_t *conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Read data from the source connection (either client or upstream).
|
||||
// 1. Read data from the source connection.
|
||||
int bytes_read = do_read(conn);
|
||||
|
||||
// 2. Forward any data we just read to the paired connection's write buffer.
|
||||
// 2. Forward any data we just read to the paired connection.
|
||||
size_t data_to_forward = buffer_available_read(&conn->read_buf);
|
||||
if (data_to_forward > 0) {
|
||||
// --- SYNTAX FIX IS HERE ---
|
||||
if (buffer_ensure_capacity(&pair->write_buf, pair->write_buf.tail + data_to_forward) < 0) {
|
||||
log_error("Failed to grow write buffer for forwarding");
|
||||
close_connection(conn->fd); // Close the pair of connections on memory error.
|
||||
close_connection(conn->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2126,52 +2147,21 @@ static void handle_forwarding(connection_t *conn) {
|
||||
conn->read_buf.data + conn->read_buf.head,
|
||||
data_to_forward);
|
||||
pair->write_buf.tail += data_to_forward;
|
||||
// --- END OF SYNTAX FIX ---
|
||||
buffer_consume(&conn->read_buf, data_to_forward);
|
||||
|
||||
// Make sure the event loop knows the pair is ready to be written to.
|
||||
modify_epoll(pair->fd, EPOLLIN | EPOLLOUT);
|
||||
}
|
||||
|
||||
// 3. Handle connection state changes (EOF or errors).
|
||||
// 3. On any read error or EOF, close the connection.
|
||||
// The new logic in `close_connection` will correctly handle the state of the pair.
|
||||
if (bytes_read <= 0 && (errno != EAGAIN && errno != EWOULDBLOCK)) {
|
||||
if (bytes_read < 0) { // A real read error occurred.
|
||||
log_debug("Read error on fd=%d while forwarding. Closing connection.", conn->fd);
|
||||
close_connection(conn->fd); // This will recursively close the pair.
|
||||
return;
|
||||
}
|
||||
|
||||
// --- ROBUST FIX FOR KEEP-ALIVE RACE CONDITION ---
|
||||
// At this point, bytes_read is 0, meaning one side has closed its connection (EOF).
|
||||
|
||||
log_info("[ROUTING-EOF] EOF on fd=%d (type=%s)", conn->fd,
|
||||
(conn->type == CONN_TYPE_CLIENT) ? "CLIENT" : "UPSTREAM");
|
||||
|
||||
if (conn->type == CONN_TYPE_UPSTREAM) {
|
||||
// **This is the critical fix.** The upstream server finished its response.
|
||||
// The client connection must be immediately reset to handle the next keep-alive request.
|
||||
if (pair->type == CONN_TYPE_CLIENT) {
|
||||
log_info("[ROUTING-KEEPALIVE] Upstream fd=%d finished. Resetting client fd=%d.", conn->fd, pair->fd);
|
||||
|
||||
// Reset client state to stop forwarding and prepare for new headers.
|
||||
pair->state = CLIENT_STATE_READING_HEADERS;
|
||||
pair->pair = NULL; // Decouple from this now-finished upstream connection.
|
||||
|
||||
// Check for pipelined requests that may have already arrived.
|
||||
if (buffer_available_read(&pair->read_buf) > 0) {
|
||||
handle_client_read(pair);
|
||||
}
|
||||
}
|
||||
// The upstream connection's job is done. Close it, leaving the client open.
|
||||
close_connection(conn->fd);
|
||||
|
||||
} else if (conn->type == CONN_TYPE_CLIENT) {
|
||||
// The client has closed its side of the connection.
|
||||
// In this case, we perform a full teardown of both connections.
|
||||
close_connection(conn->fd);
|
||||
}
|
||||
close_connection(conn->fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void handle_ssl_handshake(connection_t *conn) {
|
||||
if (!conn->ssl || conn->ssl_handshake_done) return;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user