From 18fc7ac070a4f78bddb9d3689cc25bf6841689fd Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Wed, 25 Mar 2015 16:17:18 -0500 Subject: [PATCH] TCP socket timer limits mean they're marked frozen, not EOL EOL is now only for errors. a frozen socket can still have requests using it. For auth/acct, we can't close the socket until all requests using it have finished. We can't close socket while the client is still sending packets. That's rude. For proxy sockets, most of the same applies. The only difference is that the frozen socket won't be used to proxy new requests. But retransmits will still go out the proxy socket. And replies will still be received from it. --- src/main/process.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/src/main/process.c b/src/main/process.c index 05d41ad..1ce4daa 100644 --- a/src/main/process.c +++ b/src/main/process.c @@ -776,8 +776,7 @@ static void request_done(REQUEST *request, int action) * If we're the last one, remove the listener now. */ if ((request->listener->count == 0) && - (request->listener->status == RAD_LISTEN_STATUS_EOL)) { - request->listener->status = RAD_LISTEN_STATUS_REMOVE_NOW; + (request->listener->status >= RAD_LISTEN_STATUS_FROZEN)) { event_new_fd(request->listener); } } @@ -1892,10 +1891,10 @@ static void tcp_socket_timer(void *ctx) ASSERT_MASTER; - fr_event_now(el, &now); - if (listener->status != RAD_LISTEN_STATUS_KNOWN) return; + fr_event_now(el, &now); + switch (listener->type) { #ifdef WITH_PROXY case RAD_LISTEN_PROXY: @@ -1945,7 +1944,10 @@ static void tcp_socket_timer(void *ctx) } #endif - listener->status = RAD_LISTEN_STATUS_EOL; + /* + * Mark the socket as "don't use if at all possible". + */ + listener->status = RAD_LISTEN_STATUS_FROZEN; event_new_fd(listener); return; } @@ -3657,9 +3659,17 @@ static void proxy_wait_for_reply(REQUEST *request, int action) */ if (request->home_server->server) return; + /* + * Use a new connection when the home server is + * dead, or when there's no proxy listener, or + * when the listener is failed or dead. + * + * If the listener is known or frozen, use it for + * retransmits. + */ if ((home->state == HOME_STATE_IS_DEAD) || !request->proxy_listener || - (request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) { + (request->proxy_listener->status >= RAD_LISTEN_STATUS_EOL)) { request_proxy_anew(request); return; } @@ -3726,7 +3736,7 @@ static void proxy_wait_for_reply(REQUEST *request, int action) #ifdef WITH_TCP if (!request->proxy_listener || - (request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) { + (request->proxy_listener->status >= RAD_LISTEN_STATUS_EOL)) { remove_from_proxy_hash(request); when = request->packet->timestamp; @@ -4669,7 +4679,40 @@ static int event_new_fd(rad_listen_t *this) #ifdef WITH_TCP /* - * Stop using this socket, if at all possible. + * The socket has reached a timeout. Try to close it. + */ + if (this->status == RAD_LISTEN_STATUS_FROZEN) { + /* + * Requests are still using the socket. Wait for + * them to finish. + */ + if (this->count > 0) { + struct timeval when; + listen_socket_t *sock = this->data; + + /* + * Try again to clean up the socket in 30 + * seconds. + */ + gettimeofday(&when, NULL); + when.tv_sec += 30; + + ASSERT_MASTER; + if (!fr_event_insert(el, + (fr_event_callback_t) event_new_fd, + this, &when, &sock->ev)) { + rad_panic("Failed to insert event"); + } + + return 1; + } + + fr_event_fd_delete(el, 0, this->fd); + this->status = RAD_LISTEN_STATUS_REMOVE_NOW; + } + + /* + * The socket has had a catastrophic error. Close it. */ if (this->status == RAD_LISTEN_STATUS_EOL) { /* -- 2.1.4