X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Fevent.c;h=65fcb6bc903a1d59bcb489b40e59594496b9cde7;hb=540a0515de93d99ef45f97b9114185f159587b51;hp=6ec7bc30954f1b0adbf34be8d1674ecdee1fbf08;hpb=510aebd233d2894b9093b4d133219e9736993c12;p=freeradius.git diff --git a/src/main/event.c b/src/main/event.c index 6ec7bc3..65fcb6b 100644 --- a/src/main/event.c +++ b/src/main/event.c @@ -43,7 +43,6 @@ RCSID("$Id$") extern pid_t radius_pid; extern int dont_fork; extern int check_config; -extern void force_log_reopen(void); extern char *debug_condition; /* @@ -84,11 +83,6 @@ static pthread_t NO_SUCH_CHILD_PID; */ #define PTHREAD_MUTEX_LOCK(_x) #define PTHREAD_MUTEX_UNLOCK(_x) -int thread_pool_addrequest(REQUEST *request, RAD_REQUEST_FUNP fun) -{ - radius_handle_request(request, fun); - return 1; -} #endif /* @@ -157,6 +151,10 @@ static void remove_from_request_hash(REQUEST *request) fr_packet_list_yank(pl, request->packet); request->in_request_hash = FALSE; + /* + * FIXME: Move this to a "statistics" thread? + * Or (short term) add a mutex lock around it. + */ request_stats_final(request); #ifdef WITH_TCP @@ -164,10 +162,45 @@ static void remove_from_request_hash(REQUEST *request) #endif } +static void ev_request_free(REQUEST **prequest) +{ + REQUEST *request; + + if (!prequest || !*prequest) return; + + request = *prequest; + +#ifdef WITH_COA + if (request->coa) { + /* + * Divorce the child from the parent first, + * then clean up the child. + */ + request->coa->parent = NULL; + ev_request_free(&request->coa); + } + + /* + * Divorce the parent from the child, and leave the + * parent still alive. + */ + if (request->parent && (request->parent->coa == request)) { + request->parent->coa = NULL; + } +#endif + + if (request->ev) fr_event_delete(el, &request->ev); +#ifdef WITH_PROXY + if (request->in_proxy_hash) remove_from_proxy_hash(request); +#endif + if (request->in_request_hash) remove_from_request_hash(request); + + request_free(prequest); +} + #ifdef WITH_PROXY static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply) { - int done = FALSE; RADIUS_PACKET **proxy_p; REQUEST *request; @@ -182,16 +215,8 @@ static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply) request = fr_packet2myptr(REQUEST, proxy, proxy_p); request->num_proxied_responses++; /* needs to be protected by lock */ - done = (request->num_proxied_requests == request->num_proxied_responses); PTHREAD_MUTEX_UNLOCK(&proxy_mutex); - - /* - * Catch the most common case of everything working - * correctly. - */ - if (done) remove_from_proxy_hash(request); - return request; } @@ -247,42 +272,6 @@ static void remove_from_proxy_hash(REQUEST *request) } #endif /* WITH_PROXY */ -static void ev_request_free(REQUEST **prequest) -{ - REQUEST *request; - - if (!prequest || !*prequest) return; - - request = *prequest; - -#ifdef WITH_COA - if (request->coa) { - /* - * Divorce the child from the parent first, - * then clean up the child. - */ - request->coa->parent = NULL; - ev_request_free(&request->coa); - } - - /* - * Divorce the parent from the child, and leave the - * parent still alive. - */ - if (request->parent && (request->parent->coa == request)) { - request->parent->coa = NULL; - } -#endif - - if (request->ev) fr_event_delete(el, &request->ev); -#ifdef WITH_PROXY - if (request->in_proxy_hash) remove_from_proxy_hash(request); -#endif - if (request->in_request_hash) remove_from_request_hash(request); - - request_free(prequest); -} - #ifdef WITH_TCP static int remove_all_requests(void *ctx, void *data) { @@ -377,6 +366,8 @@ retry: rcode = fr_packet_list_id_alloc(proxy_list, request->home_server->proto, request->proxy, &proxy_listener); + request->num_proxied_requests = 1; + request->num_proxied_responses = 0; PTHREAD_MUTEX_UNLOCK(&proxy_mutex); if (!rcode) { @@ -408,7 +399,7 @@ retry: if (!fr_packet_list_insert(proxy_list, &request->proxy)) { fr_packet_list_id_free(proxy_list, request->proxy); PTHREAD_MUTEX_UNLOCK(&proxy_mutex); - radlog(L_PROXY, "Failed to insert entry into proxy list"); + radlog(L_PROXY, "Failed to insert entry into proxy list."); return 0; } @@ -467,12 +458,11 @@ static void wait_for_proxy_id_to_expire(void *ctx) #endif timercmp(&now, &request->when, >)) { if (request->packet) { - RDEBUG2("Cleaning up request %d ID %d with timestamp +%d", - request->number, request->packet->id, + RDEBUG2("Cleaning up request packet ID %d with timestamp +%d", + request->packet->id, (unsigned int) (request->timestamp - fr_start_time)); } else { - RDEBUG2("Cleaning up request %d with timestamp +%d", - request->number, + RDEBUG2("Cleaning up request with timestamp +%d", (unsigned int) (request->timestamp - fr_start_time)); } @@ -490,6 +480,7 @@ static void wait_for_child_to_die(void *ctx) REQUEST *request = ctx; rad_assert(request->magic == REQUEST_MAGIC); + remove_from_request_hash(request); /* * If it's still queued (waiting for a thread to pick it @@ -501,14 +492,15 @@ static void wait_for_child_to_die(void *ctx) (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0))) { /* - * Cap delay at five minutes. + * Cap delay at max_request_time */ - if (request->delay < (USEC * 60 * 5)) { + if (request->delay < (USEC * request->root->max_request_time)) { request->delay += (request->delay >> 1); - radlog(L_INFO, "WARNING: Child is hung for request %d in component %s module %s.", - request->number, request->component, request->module); + radlog_request(L_INFO, 0, request, "WARNING: Child is hung in component %s module %s.", + request->component, request->module); } else { - RDEBUG2("Child is still stuck for request %d", + request->delay = USEC * request->root->max_request_time; + RDEBUG2("WARNING: Child is hung after \"max_request_time\" for request %u", request->number); } tv_add(&request->when, request->delay); @@ -517,8 +509,7 @@ static void wait_for_child_to_die(void *ctx) return; } - RDEBUG2("Child is responsive for request %d", request->number); - remove_from_request_hash(request); + RDEBUG2("Child is finally responsive"); #ifdef WITH_PROXY if (request->proxy) { @@ -548,8 +539,8 @@ static void cleanup_delay(void *ctx) } #endif - RDEBUG2("Cleaning up request %d ID %d with timestamp +%d", - request->number, request->packet->id, + RDEBUG2("Cleaning up request packet ID %d with timestamp +%d", + request->packet->id, (unsigned int) (request->timestamp - fr_start_time)); ev_request_free(&request); @@ -618,7 +609,7 @@ static void reject_delay(void *ctx) rad_assert(request->magic == REQUEST_MAGIC); rad_assert(request->child_state == REQUEST_REJECT_DELAY); - RDEBUG2("Sending delayed reject for request %d", request->number); + RDEBUG2("Sending delayed reject"); DEBUG_PACKET(request, request->reply, 1); @@ -686,6 +677,12 @@ static void no_response_to_ping(void *ctx) } +/* + * Note that we don't care what the value of the code field is. + * If the response has a valid (src ip/port, dst ip/port), id, + * and correctly signed Message-Authenticator, that's good + * enough. + */ static void received_response_to_ping(REQUEST *request) { home_server *home; @@ -819,7 +816,7 @@ static void ping_home_server(void *ctx) rad_assert(request->proxy_listener == NULL); if (!insert_into_proxy_hash(request)) { - radlog(L_PROXY, "Failed inserting status check %d into proxy hash. Discarding it.", + radlog(L_PROXY, "Failed to insert status check %d into proxy list. Discarding it.", request->number); ev_request_free(&request); return; @@ -930,9 +927,7 @@ static void proxy_fallback_handler(REQUEST *request) request->child_state = REQUEST_QUEUED; rad_assert(request->proxy != NULL); - if (!thread_pool_addrequest(request, virtual_server_handler)) { - request->child_state = REQUEST_DONE; - } + thread_pool_addrequest(request, virtual_server_handler); #ifdef HAVE_PTHREAD_H /* @@ -957,10 +952,10 @@ static int setup_post_proxy_fail(REQUEST *request) request->child_state = REQUEST_RUNNING; if (request->packet->code == PW_AUTHENTICATION_REQUEST) { - dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Authentication"); + dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-Authentication"); } else if (request->packet->code == PW_ACCOUNTING_REQUEST) { - dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Accounting"); + dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-Accounting"); #ifdef WITH_COA /* @@ -970,10 +965,10 @@ static int setup_post_proxy_fail(REQUEST *request) request->packet->code &= 0xff; /* restore it */ if (request->proxy->code == PW_COA_REQUEST) { - dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-CoA"); + dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-CoA"); } else if (request->proxy->code == PW_DISCONNECT_REQUEST) { - dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Disconnect"); + dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-Disconnect"); } else { return 0; } @@ -983,16 +978,16 @@ static int setup_post_proxy_fail(REQUEST *request) return 0; } - if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail"); + if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail"); if (!dval) { - pairdelete(&request->config_items, PW_POST_PROXY_TYPE); + pairdelete(&request->config_items, PW_POST_PROXY_TYPE, 0); return 0; } - vp = pairfind(request->config_items, PW_POST_PROXY_TYPE); + vp = pairfind(request->config_items, PW_POST_PROXY_TYPE, 0); if (!vp) vp = radius_paircreate(request, &request->config_items, - PW_POST_PROXY_TYPE, PW_TYPE_INTEGER); + PW_POST_PROXY_TYPE, 0, PW_TYPE_INTEGER); vp->vp_integer = dval->value; rad_assert(request->proxy_reply == NULL); @@ -1098,8 +1093,8 @@ static void no_response_to_proxied_request(void *ctx) * well. */ if (home->no_response_fail) { - radlog(L_ERR, "Rejecting request %d (proxy Id %d) due to lack of any response from home server %s port %d", - request->number, request->proxy->id, + radlog_request(L_ERR, 0, request, "Rejecting request (proxy Id %d) due to lack of any response from home server %s port %d", + request->proxy->id, inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), @@ -1147,33 +1142,53 @@ static void no_response_to_proxied_request(void *ctx) } #endif - if (home->state == HOME_STATE_IS_DEAD) { - rad_assert(home->ev != NULL); /* or it will never wake up */ + /* + * If it's not alive, don't try to make it a zombie. + */ + if (home->state != HOME_STATE_ALIVE) { + /* + * Don't check home->ev due to race conditions. + */ return; } /* - * Enable the zombie period when we notice that the home - * server hasn't responded. We do NOT back-date the start - * of the zombie period. + * We've received a real packet recently. Don't mark the + * server as zombie until we've received NO packets for a + * while. The "1/4" of zombie period was chosen rather + * arbitrarily. It's a balance between too short, which + * gives quick fail-over and fail-back, or too long, + * where the proxy still sends packets to an unresponsive + * home server. */ - if (home->state == HOME_STATE_ALIVE) { - home->state = HOME_STATE_ZOMBIE; - home->zombie_period_start = now; - fr_event_delete(el, &home->ev); - home->currently_outstanding = 0; - home->num_received_pings = 0; - - radlog(L_PROXY, "Marking home server %s port %d as zombie (it looks like it is dead).", - inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr, - buffer, sizeof(buffer)), - home->port); - - /* - * Start pinging the home server. - */ - ping_home_server(home); + if ((home->last_packet + ((home->zombie_period + 3) / 4)) >= now.tv_sec) { + return; } + + /* + * Enable the zombie period when we notice that the home + * server hasn't responded for a while. We back-date the + * zombie period to when we last received a response from + * the home server. + */ + home->state = HOME_STATE_ZOMBIE; + + home->zombie_period_start.tv_sec = home->last_packet; + home->zombie_period_start.tv_sec = USEC / 2; + + fr_event_delete(el, &home->ev); + home->currently_outstanding = 0; + home->num_received_pings = 0; + + radlog(L_PROXY, "Marking home server %s port %d as zombie (it looks like it is dead).", + inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr, + buffer, sizeof(buffer)), + home->port); + + /* + * Start pinging the home server. + */ + ping_home_server(home); } #endif @@ -1185,6 +1200,7 @@ static void wait_a_bit(void *ctx) rad_assert(request->magic == REQUEST_MAGIC); +#ifdef HAVE_PTHREAD_H /* * The socket was closed. Tell the request that * there is no point in continuing. @@ -1192,6 +1208,7 @@ static void wait_a_bit(void *ctx) if (request->listener->status != RAD_LISTEN_STATUS_KNOWN) { goto stop_processing; } +#endif #ifdef WITH_COA /* @@ -1213,6 +1230,25 @@ static void wait_a_bit(void *ctx) switch (request->child_state) { case REQUEST_QUEUED: case REQUEST_RUNNING: + /* + * If we're not thread-capable, OR we're capable, + * but have been told to run without threads, and + * the request is still running. This is usually + * because the request was proxied, and the home + * server didn't respond. + */ +#ifdef HAVE_PTHREAD_H + if (!have_children) +#endif + { + goto done; + } + +#ifdef HAVE_PTHREAD_H + /* + * If we have threads, wait for the child thread + * to stop. + */ when = request->received; when.tv_sec += request->root->max_request_time; @@ -1229,24 +1265,18 @@ static void wait_a_bit(void *ctx) * Request still has more time. Continue * waiting. */ - if (timercmp(&now, &when, <) || - ((request->listener->type == RAD_LISTEN_DETAIL) && - (request->child_state == REQUEST_QUEUED))) { + if (timercmp(&now, &when, <)) { if (request->delay < (USEC / 10)) { request->delay = USEC / 10; } request->delay += request->delay >> 1; -#ifdef WITH_DETAIL /* - * Cap wait at some sane value for detail - * files. + * Cap delays at something reasonable. */ - if ((request->listener->type == RAD_LISTEN_DETAIL) && - (request->delay > (request->root->max_request_time * USEC))) { + if (request->delay > (request->root->max_request_time * USEC)) { request->delay = request->root->max_request_time * USEC; } -#endif request->when = now; tv_add(&request->when, request->delay); @@ -1255,7 +1285,8 @@ static void wait_a_bit(void *ctx) } stop_processing: -#if defined(HAVE_PTHREAD_H) || defined(WITH_PROXY) + request->master_state = REQUEST_STOP_PROCESSING; + /* * A child thread MAY still be running on the * request. Ask the thread to stop working on @@ -1263,41 +1294,30 @@ static void wait_a_bit(void *ctx) */ if (have_children && (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) { - request->master_state = REQUEST_STOP_PROCESSING; - - radlog(L_ERR, "WARNING: Unresponsive child for request %d, in module %s component %s", + radlog(L_ERR, "WARNING: Unresponsive child for request %u, in component %s module %s", request->number, - request->module ? request->module : "", - request->component ? request->component : ""); - - request->delay = USEC / 4; - tv_add(&request->when, request->delay); - callback = wait_for_child_to_die; - break; + request->component ? request->component : "", + request->module ? request->module : ""); + } + + request->delay = USEC; + tv_add(&request->when, request->delay); + callback = wait_for_child_to_die; + break; #endif /* - * Else no child thread is processing the - * request. We probably should have just marked - * the request as 'done' elsewhere, like in the - * post-proxy-fail handler. But doing that would - * involve checking for max_request_time in - * multiple places, so this may be simplest. - */ - request->child_state = REQUEST_DONE; - /* FALL-THROUGH */ - - /* * Mark the request as no longer running, * and clean it up. */ case REQUEST_DONE: + done: #ifdef HAVE_PTHREAD_H request->child_pid = NO_SUCH_CHILD_PID; #endif -#ifdef WTH_COA +#ifdef WITH_COA /* * This is a CoA request. It's been divorced * from everything else, so we clean it up now. @@ -1314,7 +1334,6 @@ static void wait_a_bit(void *ctx) return; } #endif - request_stats_final(request); cleanup_delay(request); return; @@ -1323,7 +1342,6 @@ static void wait_a_bit(void *ctx) #ifdef HAVE_PTHREAD_H request->child_pid = NO_SUCH_CHILD_PID; #endif - request_stats_final(request); case REQUEST_PROXIED: rad_assert(request->next_callback != NULL); @@ -1350,7 +1368,7 @@ static void wait_a_bit(void *ctx) * mode, with no threads... */ if (!callback) { - RDEBUG("WARNING: Internal sanity check failed in event handler for request %d: Discarding the request!", request->number); + RDEBUG("WARNING: Internal sanity check failed in event handler: Discarding the request!"); ev_request_free(&request); return; } @@ -1386,7 +1404,7 @@ static int update_event_timestamp(RADIUS_PACKET *packet, time_t when) { VALUE_PAIR *vp; - vp = pairfind(packet->vps, PW_EVENT_TIMESTAMP); + vp = pairfind(packet->vps, PW_EVENT_TIMESTAMP, 0); if (!vp) return 0; vp->vp_date = when; @@ -1484,28 +1502,34 @@ static void retransmit_coa_request(void *ctx) * Id. */ RADIUS_PACKET old = *request->proxy; + home_server *home = request->home_server; + rad_listen_t *listener = request->proxy_listener; /* * Don't free the old Id on error. */ if (!insert_into_proxy_hash(request)) { - radlog(L_PROXY,"Failed re-inserting CoA request into proxy hash."); + radlog(L_PROXY,"Failed to insert retransmission of CoA request into proxy list."); return; } /* - * Now that we have a new Id, free the old one. + * Now that we have a new Id, free the old one + * and update the various statistics. */ PTHREAD_MUTEX_LOCK(&proxy_mutex); fr_packet_list_yank(proxy_list, &old); fr_packet_list_id_free(proxy_list, &old); + if (home) home->currently_outstanding--; +#ifdef WITH_TCP + if (listener) listener->count--; +#endif PTHREAD_MUTEX_UNLOCK(&proxy_mutex); - request->num_proxied_requests = 0; - request->num_proxied_responses = 0; + } else { /* FIXME: protect by a mutex? */ + request->num_proxied_requests++; } - request->num_proxied_requests++; request->num_coa_requests++; /* is NOT reset by code 3 lines above! */ request->proxy_listener->send(request->proxy_listener, @@ -1531,9 +1555,9 @@ static int originated_coa_request(REQUEST *request) /* * Check whether we want to originate one, or cancel one. */ - vp = pairfind(request->config_items, PW_SEND_COA_REQUEST); + vp = pairfind(request->config_items, PW_SEND_COA_REQUEST, 0); if (!vp && request->coa) { - vp = pairfind(request->coa->proxy->vps, PW_SEND_COA_REQUEST); + vp = pairfind(request->coa->proxy->vps, PW_SEND_COA_REQUEST, 0); } if (vp) { @@ -1552,18 +1576,18 @@ static int originated_coa_request(REQUEST *request) * src_ipaddr will be set up in proxy_encode. */ memset(&ipaddr, 0, sizeof(ipaddr)); - vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IP_ADDRESS); + vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IP_ADDRESS, 0); if (vp) { ipaddr.af = AF_INET; ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; } else if ((vp = pairfind(coa->proxy->vps, - PW_PACKET_DST_IPV6_ADDRESS)) != NULL) { + PW_PACKET_DST_IPV6_ADDRESS, 0)) != NULL) { ipaddr.af = AF_INET6; ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; } else if ((vp = pairfind(coa->proxy->vps, - PW_HOME_SERVER_POOL)) != NULL) { + PW_HOME_SERVER_POOL, 0)) != NULL) { coa->home_pool = home_pool_byname(vp->vp_strvalue, HOME_TYPE_COA); if (!coa->home_pool) { @@ -1604,7 +1628,7 @@ static int originated_coa_request(REQUEST *request) } else if (!coa->home_server) { int port = PW_COA_UDP_PORT; - vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT); + vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT, 0); if (vp) port = vp->vp_integer; coa->home_server = home_server_find(&ipaddr, port, IPPROTO_UDP); @@ -1616,7 +1640,7 @@ static int originated_coa_request(REQUEST *request) } } - vp = pairfind(coa->proxy->vps, PW_PACKET_TYPE); + vp = pairfind(coa->proxy->vps, PW_PACKET_TYPE, 0); if (vp) { switch (vp->vp_integer) { case PW_COA_REQUEST: @@ -1653,7 +1677,7 @@ static int originated_coa_request(REQUEST *request) /* * Call the pre-proxy routines. */ - vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE); + vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE, 0); if (vp) { RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue); pre_proxy_type = vp->vp_integer; @@ -1691,7 +1715,7 @@ static int originated_coa_request(REQUEST *request) coa->proxy->dst_port = coa->home_server->port; if (!insert_into_proxy_hash(coa)) { - radlog(L_PROXY, "Failed inserting CoA request into proxy hash."); + radlog(L_PROXY, "Failed to insert CoA request into proxy list."); goto fail; } @@ -1740,8 +1764,6 @@ static int originated_coa_request(REQUEST *request) * another thread may have picked it up. Don't * touch it! */ - request->num_proxied_requests = 1; - request->num_proxied_responses = 0; request->child_pid = NO_SUCH_CHILD_PID; update_event_timestamp(request->proxy, request->proxy_when.tv_sec); @@ -1772,7 +1794,7 @@ static int process_proxy_reply(REQUEST *request) * Run the packet through the post-proxy stage, * BEFORE playing games with the attributes. */ - vp = pairfind(request->config_items, PW_POST_PROXY_TYPE); + vp = pairfind(request->config_items, PW_POST_PROXY_TYPE, 0); if (vp) { RDEBUG2(" Found Post-Proxy-Type %s", vp->vp_strvalue); post_proxy_type = vp->vp_integer; @@ -1809,7 +1831,7 @@ static int process_proxy_reply(REQUEST *request) * the reply. These include Proxy-State * attributes from us and remote server. */ - pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE); + pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE, 0); /* * Add the attributes left in the proxy @@ -1858,9 +1880,9 @@ static int request_pre_handler(REQUEST *request) */ if (request->packet->dst_port == 0) { request->username = pairfind(request->packet->vps, - PW_USER_NAME); + PW_USER_NAME, 0); request->password = pairfind(request->packet->vps, - PW_USER_PASSWORD); + PW_USER_PASSWORD, 0); return 1; } @@ -1869,15 +1891,20 @@ static int request_pre_handler(REQUEST *request) * Put the decoded packet into it's proper place. */ if (request->proxy_reply != NULL) { + rcode = request->proxy_listener->decode(request->proxy_listener, request); + DEBUG_PACKET(request, request->proxy_reply, 0); + /* - * FIXME: For now, we can only proxy RADIUS packets. - * - * In order to proxy other packets, we need to - * somehow cache the "decode" function. + * Pro-actively remove it from the proxy hash. + * This is later than in 2.1.x, but it means that + * the replies are authenticated before being + * removed from the hash. */ - rcode = rad_decode(request->proxy_reply, request->proxy, - request->home_server->secret); - DEBUG_PACKET(request, request->proxy_reply, 0); + if ((rcode == 0) && + (request->num_proxied_requests <= request->num_proxied_responses)) { + remove_from_proxy_hash(request); + } + } else #endif if (request->packet->vps == NULL) { @@ -1913,14 +1940,14 @@ static int request_pre_handler(REQUEST *request) if (!request->username) { request->username = pairfind(request->packet->vps, - PW_USER_NAME); + PW_USER_NAME, 0); } #ifdef WITH_PROXY if (request->proxy) { return process_proxy_reply(request); -#endif } +#endif return 1; } @@ -1935,13 +1962,20 @@ static int proxy_request(REQUEST *request) struct timeval when; char buffer[128]; +#ifdef WITH_COA + if (request->coa) { + RDEBUG("WARNING: Cannot proxy and originate CoA packets at the same time. Cancelling CoA request"); + ev_request_free(&request->coa); + } +#endif + if (request->home_server->server) { - RDEBUG("ERROR: Cannot perform real proxying to a virtual server."); + RDEBUG("ERROR: Cannot proxy to a virtual server."); return 0; } if (!insert_into_proxy_hash(request)) { - radlog(L_PROXY, "Failed inserting request into proxy hash."); + radlog(L_PROXY, "Failed to insert request into proxy list."); return 0; } @@ -1962,8 +1996,7 @@ static int proxy_request(REQUEST *request) } request->next_callback = no_response_to_proxied_request; - RDEBUG2("Proxying request %d to home server %s port %d", - request->number, + RDEBUG2("Proxying request to home server %s port %d", inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), @@ -1976,8 +2009,6 @@ static int proxy_request(REQUEST *request) * another thread may have picked it up. Don't * touch it! */ - request->num_proxied_requests = 1; - request->num_proxied_responses = 0; #ifdef HAVE_PTHREAD_H request->child_pid = NO_SUCH_CHILD_PID; #endif @@ -2092,11 +2123,11 @@ static int successfully_proxied_request(REQUEST *request) return 0; } - realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM); + realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM, 0); if (!realmpair || (realmpair->length == 0)) { int pool_type; - vp = pairfind(request->config_items, PW_HOME_SERVER_POOL); + vp = pairfind(request->config_items, PW_HOME_SERVER_POOL, 0); if (!vp) return 0; switch (request->packet->code) { @@ -2197,7 +2228,7 @@ found_pool: * requests. */ if (realm && (realm->striprealm == TRUE) && - (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) { + (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME, 0)) != NULL) { /* * If there's a Stripped-User-Name attribute in * the request, then use THAT as the User-Name @@ -2211,10 +2242,10 @@ found_pool: * from the vps list, and making the new * User-Name the head of the vps list. */ - vp = pairfind(request->proxy->vps, PW_USER_NAME); + vp = pairfind(request->proxy->vps, PW_USER_NAME, 0); if (!vp) { vp = radius_paircreate(request, NULL, - PW_USER_NAME, PW_TYPE_STRING); + PW_USER_NAME, 0, PW_TYPE_STRING); rad_assert(vp != NULL); /* handled by above function */ /* Insert at the START of the list */ vp->next = request->proxy->vps; @@ -2236,10 +2267,10 @@ found_pool: * anymore - we changed it. */ if ((request->packet->code == PW_AUTHENTICATION_REQUEST) && - pairfind(request->proxy->vps, PW_CHAP_PASSWORD) && - pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) { + pairfind(request->proxy->vps, PW_CHAP_PASSWORD, 0) && + pairfind(request->proxy->vps, PW_CHAP_CHALLENGE, 0) == NULL) { vp = radius_paircreate(request, &request->proxy->vps, - PW_CHAP_CHALLENGE, PW_TYPE_OCTETS); + PW_CHAP_CHALLENGE, 0, PW_TYPE_OCTETS); vp->length = AUTH_VECTOR_LEN; memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN); } @@ -2249,7 +2280,7 @@ found_pool: * doesn't need it. */ vp = radius_paircreate(request, &request->proxy->vps, - PW_PROXY_STATE, PW_TYPE_OCTETS); + PW_PROXY_STATE, 0, PW_TYPE_OCTETS); snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), "%d", request->packet->id); vp->length = strlen(vp->vp_strvalue); @@ -2263,7 +2294,7 @@ found_pool: /* * Call the pre-proxy routines. */ - vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE); + vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE, 0); if (vp) { RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue); pre_proxy_type = vp->vp_integer; @@ -2319,7 +2350,7 @@ found_pool: } if (!proxy_request(request)) { - RDEBUG("ERROR: Failed to proxy request %d", request->number); + RDEBUG("ERROR: Failed to proxy request"); return -1; } @@ -2336,7 +2367,7 @@ static void request_post_handler(REQUEST *request) if ((request->master_state == REQUEST_STOP_PROCESSING) || (request->parent && (request->parent->master_state == REQUEST_STOP_PROCESSING))) { - RDEBUG2("Request %d was cancelled.", request->number); + RDEBUG2("request was cancelled."); #ifdef HAVE_PTHREAD_H request->child_pid = NO_SUCH_CHILD_PID; #endif @@ -2368,7 +2399,7 @@ static void request_post_handler(REQUEST *request) */ if ((request->packet->code == PW_AUTHENTICATION_REQUEST) && (request->reply->code == 0) && - ((vp = pairfind(request->config_items, PW_AUTH_TYPE)) != NULL) && + ((vp = pairfind(request->config_items, PW_AUTH_TYPE, 0)) != NULL) && (vp->vp_integer == PW_AUTHTYPE_REJECT)) { request->reply->code = PW_AUTHENTICATION_REJECT; } @@ -2403,6 +2434,13 @@ static void request_post_handler(REQUEST *request) * OR we proxied it internally to a virutal server. */ } + +#ifdef WITH_COA + else if (request->proxy && request->coa) { + RDEBUG("WARNING: Cannot proxy and originate CoA packets at the same time. Cancelling CoA request"); + ev_request_free(&request->coa); + } +#endif #endif /* @@ -2423,7 +2461,7 @@ static void request_post_handler(REQUEST *request) /* * Copy Proxy-State from the request to the reply. */ - vp = paircopy2(request->packet->vps, PW_PROXY_STATE); + vp = paircopy2(request->packet->vps, PW_PROXY_STATE, 0); if (vp) pairadd(&request->reply->vps, vp); #endif @@ -2439,15 +2477,13 @@ static void request_post_handler(REQUEST *request) * Check if the lack of response is intentional. */ vp = pairfind(request->config_items, - PW_RESPONSE_PACKET_TYPE); + PW_RESPONSE_PACKET_TYPE, 0); if (!vp) { - RDEBUG2("There was no response configured: rejecting request %d", - request->number); + RDEBUG2("There was no response configured: rejecting request"); request->reply->code = PW_AUTHENTICATION_REJECT; } else if (vp->vp_integer == 256) { - RDEBUG2("Not responding to request %d", - request->number); + RDEBUG2("Not responding to request"); /* * Force cleanup after a long @@ -2470,7 +2506,7 @@ static void request_post_handler(REQUEST *request) * Post-Auth-Type = Reject */ if (request->reply->code == PW_AUTHENTICATION_REJECT) { - pairdelete(&request->config_items, PW_POST_AUTH_TYPE); + pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0); vp = radius_pairmake(request, &request->config_items, "Post-Auth-Type", "Reject", T_OP_SET); @@ -2486,8 +2522,7 @@ static void request_post_handler(REQUEST *request) when.tv_sec += request->root->reject_delay; if (timercmp(&when, &request->next_when, >)) { - RDEBUG2("Delaying reject of request %d for %d seconds", - request->number, + RDEBUG2("Delaying reject for %d seconds", request->root->reject_delay); request->next_when = when; request->next_callback = reject_delay; @@ -2538,8 +2573,11 @@ static void request_post_handler(REQUEST *request) * and it should re-send it. * If configured, encode, sign, and send. */ - if ((request->reply->code != 0) || - (request->listener->type == RAD_LISTEN_DETAIL)) { + if ((request->reply->code != 0) +#ifdef WITH_DETAIL + || (request->listener->type == RAD_LISTEN_DETAIL) +#endif + ) { DEBUG_PACKET(request, request->reply, 1); request->listener->send(request->listener, request); } @@ -2547,10 +2585,14 @@ static void request_post_handler(REQUEST *request) #ifdef WITH_COA /* * Now that we've completely processed the request, - * see if we need to originate a CoA request. + * see if we need to originate a CoA request. But ONLY + * if it wasn't proxied. */ - if (request->coa || - (pairfind(request->config_items, PW_SEND_COA_REQUEST) != NULL)) { + if (!request->proxy && + (request->packet->code != PW_COA_REQUEST) && + (request->packet->code != PW_DISCONNECT_REQUEST) && + (request->coa || + (pairfind(request->config_items, PW_SEND_COA_REQUEST, 0) != NULL))) { if (!originated_coa_request(request)) { RDEBUG2("Do CoA Fail handler here"); } @@ -2593,7 +2635,7 @@ static void request_post_handler(REQUEST *request) } #endif - RDEBUG2("Finished request %d.", request->number); + RDEBUG2("Finished request."); rad_assert(child_state >= 0); request->child_state = child_state; @@ -2604,12 +2646,101 @@ static void request_post_handler(REQUEST *request) } -static void received_retransmit(REQUEST *request, const RADCLIENT *client) -{ #ifdef WITH_PROXY - char buffer[128]; +static void rad_retransmit_packet(REQUEST *request) +{ + char buffer[256]; + +#ifdef WITH_TCP + if (request->home_server->proto == IPPROTO_TCP) { + DEBUG2("Suppressing duplicate proxied request to home server %s port %d proto TCP - ID: %d", + inet_ntop(request->proxy->dst_ipaddr.af, + &request->proxy->dst_ipaddr.ipaddr, + buffer, sizeof(buffer)), + request->proxy->dst_port, + request->proxy->id); + return; /* don't do anything else */ + } +#endif + + RDEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d", + inet_ntop(request->proxy->dst_ipaddr.af, + &request->proxy->dst_ipaddr.ipaddr, + buffer, sizeof(buffer)), + request->proxy->dst_port, + request->proxy->id); + request->num_proxied_requests++; + + DEBUG_PACKET(request, request->proxy, 1); + request->proxy_listener->send(request->proxy_listener, + request); +} + + +static int rad_retransmit(REQUEST *request) +{ + /* + * If we've just discovered that the home server + * is dead, OR the socket has been closed, look for + * another connection to a home server. + */ + if ((request->home_server->state == HOME_STATE_IS_DEAD) || + (request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) { + home_server *home; + + remove_from_proxy_hash(request); + + home = home_server_ldb(NULL, request->home_pool, request); + if (!home) { + RDEBUG2("ERROR: Failed to find live home server for request"); + no_home_servers: + /* + * Do post-request processing, + * and any insertion of necessary + * events. + */ + post_proxy_fail_handler(request); + return 1; + } + + request->proxy->code = request->packet->code; + + /* + * Free the old packet, to force re-encoding + */ + free(request->proxy->data); + request->proxy->data = NULL; + request->proxy->data_len = 0; + + /* + * This request failed over to a virtual + * server. Push it back onto the queue + * to be processed. + */ + if (request->home_server->server) { + proxy_fallback_handler(request); + return 1; + } + + /* + * Try to proxy the request. + */ + if (!proxy_request(request)) { + RDEBUG("ERROR: Failed to re-proxy request"); + goto no_home_servers; + } + return 1; + } /* else the home server is still alive */ + + rad_retransmit_packet(request); + + return 1; +} #endif +static void received_retransmit(REQUEST *request, const RADCLIENT *client) +{ + RAD_STATS_TYPE_INC(request->listener, total_dup_requests); RAD_STATS_CLIENT_INC(request->listener, client, total_dup_requests); @@ -2620,7 +2751,7 @@ static void received_retransmit(REQUEST *request, const RADCLIENT *client) discard: #endif radlog(L_ERR, "Discarding duplicate request from " - "client %s port %d - ID: %d due to unfinished request %d", + "client %s port %d - ID: %d due to unfinished request %u", client->shortname, request->packet->src_port,request->packet->id, request->number); @@ -2654,90 +2785,25 @@ static void received_retransmit(REQUEST *request, const RADCLIENT *client) check_for_zombie_home_server(request); /* - * If we've just discovered that the home server - * is dead, OR the socket has been closed, look for - * another connection to a home server. + * Home server is still alive, and the proxy + * socket is OK. Just re-send the packet. */ - if (((request->packet->dst_port != 0) && - (request->home_server->state == HOME_STATE_IS_DEAD)) || - (request->proxy_listener->status != RAD_LISTEN_STATUS_KNOWN)) { - home_server *home; - - remove_from_proxy_hash(request); - - home = home_server_ldb(NULL, request->home_pool, request); - if (!home) { - RDEBUG2("Failed to find live home server for request %d", request->number); - no_home_servers: - /* - * Do post-request processing, - * and any insertion of necessary - * events. - */ - post_proxy_fail_handler(request); - return; - } - - request->proxy->code = request->packet->code; - - /* - * Free the old packet, to force re-encoding - */ - free(request->proxy->data); - request->proxy->data = NULL; - request->proxy->data_len = 0; - - /* - * This request failed over to a virtual - * server. Push it back onto the queue - * to be processed. - */ - if (request->home_server->server) { - proxy_fallback_handler(request); - return; - } - - /* - * Try to proxy the request. - */ - if (!proxy_request(request)) { - RDEBUG("ERROR: Failed to re-proxy request %d", request->number); - goto no_home_servers; - } - - /* - * This code executes in the main server - * thread, so there's no need for locking. - */ - rad_assert(request->next_callback != NULL); - INSERT_EVENT(request->next_callback, request); - request->next_callback = NULL; - return; - } /* else the home server is still alive */ - -#ifdef WITH_TCP - if (request->home_server->proto == IPPROTO_TCP) { - DEBUG2("Suppressing duplicate proxied request to home server %s port %d proto TCP - ID: %d", - inet_ntop(request->proxy->dst_ipaddr.af, - &request->proxy->dst_ipaddr.ipaddr, - buffer, sizeof(buffer)), - request->proxy->dst_port, - request->proxy->id); + if ((request->home_server->state != HOME_STATE_IS_DEAD) && + (request->proxy_listener->status == RAD_LISTEN_STATUS_KNOWN)) { + rad_retransmit_packet(request); break; } -#endif - RDEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d", - inet_ntop(request->proxy->dst_ipaddr.af, - &request->proxy->dst_ipaddr.ipaddr, - buffer, sizeof(buffer)), - request->proxy->dst_port, - request->proxy->id); - request->num_proxied_requests++; + /* + * Otherwise, we need to fail over to another + * home server, and possibly run "post-proxy-type + * fail". Add an event waiting for the child to + * have a result. + */ + INSERT_EVENT(wait_a_bit, request); - DEBUG_PACKET(request, request->proxy, 1); - request->proxy_listener->send(request->proxy_listener, - request); + request->priority = RAD_LISTEN_PROXY; + thread_pool_addrequest(request, rad_retransmit); break; #endif @@ -2780,7 +2846,7 @@ static void received_conflicting_request(REQUEST *request, const RADCLIENT *client) { radlog(L_ERR, "Received conflicting packet from " - "client %s port %d - ID: %d due to unfinished request %d. Giving up on old request.", + "client %s port %d - ID: %d due to unfinished request %u. Giving up on old request.", client->shortname, request->packet->src_port, request->packet->id, request->number); @@ -2906,7 +2972,7 @@ int received_request(rad_listen_t *listener, */ if ((request->reply->code != 0) && request->reply->data) { - radlog(L_INFO, "WARNING: Allowing fast client %s port %d - ID: %d for recent request %d.", + radlog(L_INFO, "WARNING: Allowing fast client %s port %d - ID: %d for recent request %u.", client->shortname, packet->src_port, packet->id, request->number); @@ -2929,7 +2995,7 @@ int received_request(rad_listen_t *listener, */ if (timercmp(&when, &request->received, <)) { radlog(L_ERR, "Discarding conflicting packet from " - "client %s port %d - ID: %d due to recent request %d.", + "client %s port %d - ID: %d due to recent request %u.", client->shortname, packet->src_port, packet->id, request->number); @@ -2953,7 +3019,10 @@ int received_request(rad_listen_t *listener, /* * We may want to quench the new request. */ - if ((listener->type != RAD_LISTEN_DETAIL) && + if ( +#ifdef WITH_DETAIL + (listener->type != RAD_LISTEN_DETAIL) && +#endif !can_handle_new_request(packet, client, root)) { return 0; } @@ -2998,7 +3067,7 @@ int received_request(rad_listen_t *listener, * Remember the request in the list. */ if (!fr_packet_list_insert(pl, &request->packet)) { - radlog(L_ERR, "Failed to insert request %d in the list of live requests: discarding", request->number); + radlog(L_ERR, "Failed to insert request %u in the list of live requests: discarding", request->number); ev_request_free(&request); return 0; } @@ -3060,7 +3129,10 @@ REQUEST *received_proxy_response(RADIUS_PACKET *packet) REQUEST *request; /* - * Also removes from the proxy hash if responses == requests + * Lookup *without* removal. In versions prior to 2.2.0, + * this did lookup *and* removal. That method allowed + * attackers to spoof replies that caused entries to be + * removed from the proxy hash prior to validation. */ request = lookup_in_proxy_hash(packet); @@ -3074,53 +3146,80 @@ REQUEST *received_proxy_response(RADIUS_PACKET *packet) } /* - * We haven't replied to the NAS, but we have seen an - * earlier reply from the home server. Ignore this packet, - * as we're likely still processing the previous reply. + * There's a reply: discard it if it's a conflicting one. */ if (request->proxy_reply) { + /* + * ? The home server gave us a new proxy + * reply which doesn't match the old + * one. Delete it. + */ if (memcmp(request->proxy_reply->vector, packet->vector, - sizeof(request->proxy_reply->vector)) == 0) { - RDEBUG2("Discarding duplicate reply from host %s port %d - ID: %d for request %d", - inet_ntop(packet->src_ipaddr.af, - &packet->src_ipaddr.ipaddr, - buffer, sizeof(buffer)), - packet->src_port, packet->id, - request->number); - } else { - /* - * ? The home server gave us a new proxy - * reply which doesn't match the old - * one. Delete it. - */ + sizeof(request->proxy_reply->vector)) != 0) { RDEBUG2("Ignoring conflicting proxy reply"); - } + - /* assert that there's an event queued for request? */ + /* assert that there's an event queued for request? */ + return NULL; + } /* else it had previously passed verification */ + + /* + * Verify the packet before doing ANYTHING with + * it. This means we're doing more MD5 checks in + * the server core. However, we can fix that by + * moving to multiple threads listening on + * sockets. + * + * We do this AFTER looking the request up in the + * hash, and AFTER checking if we saw a previous + * request. This helps minimize the DoS effect + * of people attacking us with spoofed packets. + * + * FIXME: move the "read from proxy socket" code + * into one (or more) threads. Have it read from + * the socket, do the validation, and write a + * pointer to the packet into a pipe? Or queue it + * to the main server? + */ + } else if (rad_verify(packet, request->proxy, + request->home_server->secret) != 0) { + DEBUG("Ignoring spoofed proxy reply. Signature is invalid"); return NULL; } /* - * Verify the packet before doing ANYTHING with it. This - * means we're doing more MD5 checks in the server core. - * However, we can fix that by moving to multiple threads - * listening on sockets. - * - * We do this AFTER looking the request up in the hash, - * and AFTER vhecking if we saw a previous request. This - * helps minimize the DoS effect of people attacking us - * with spoofed packets. + * Check (again) if it's a duplicate reply. We do this + * after deleting the packet from the proxy hash. */ - if (rad_verify(packet, request->proxy, - request->home_server->secret) != 0) { - DEBUG("Ignoring spoofed proxy reply. Signature is invalid"); - return NULL; + if (request->proxy_reply) { + RDEBUG2("Discarding duplicate reply from host %s port %d - ID: %d", + inet_ntop(packet->src_ipaddr.af, + &packet->src_ipaddr.ipaddr, + buffer, sizeof(buffer)), + packet->src_port, packet->id); } gettimeofday(&now, NULL); /* + * "ping" packets have a different algorithm for marking + * a home server alive. They also skip all of the CoA, + * etc. checks. + */ + if (!request->packet) { + request->proxy_reply = packet; +#ifdef WITH_TCP + rad_assert(request->home_server != NULL); + if (request->home_server->proto != IPPROTO_TCP) +#endif + received_response_to_ping(request); + request->proxy_reply = NULL; /* caller will free it */ + ev_request_free(&request); + return NULL; + } + + /* * Maybe move this earlier in the decision process? * Having it here means that late or duplicate proxy * replies no longer get the home server marked as @@ -3130,10 +3229,11 @@ REQUEST *received_proxy_response(RADIUS_PACKET *packet) * receive a packet? Setting this here means that we * mark it alive on *any* packet, even if it's lost all * of the *other* packets in the last 10s. + * + * This behavior could be configurable. */ - if (request->proxy->code != PW_STATUS_SERVER) { - request->home_server->state = HOME_STATE_ALIVE; - } + request->home_server->state = HOME_STATE_ALIVE; + request->home_server->last_packet = now.tv_sec; #ifdef WITH_COA /* @@ -3150,6 +3250,18 @@ REQUEST *received_proxy_response(RADIUS_PACKET *packet) request->parent->coa = NULL; request->parent = NULL; + /* + * The proxied packet was different from the + * original packet, AND the proxied packet was + * a CoA: allow it. + */ + } else if ((request->packet->code != request->proxy->code) && + ((request->proxy->code == PW_COA_REQUEST) || + (request->proxy->code == PW_DISCONNECT_REQUEST))) { + /* + * It's already divorced: do nothing. + */ + } else /* * Skip the next set of checks, as the original @@ -3170,7 +3282,7 @@ REQUEST *received_proxy_response(RADIUS_PACKET *packet) RDEBUG2("Ignoring proxy reply that arrived after we sent a reply to the NAS"); return NULL; } - + #ifdef WITH_STATS /* * The average includes our time to receive packets and @@ -3195,7 +3307,7 @@ REQUEST *received_proxy_response(RADIUS_PACKET *packet) case REQUEST_REJECT_DELAY: case REQUEST_CLEANUP_DELAY: case REQUEST_DONE: - radlog(L_ERR, "Reply from home server %s port %d - ID: %d arrived too late for request %d. Try increasing 'retry_delay' or 'max_request_time'", + radlog(L_ERR, "Reply from home server %s port %d - ID: %d arrived too late for request %u. Try increasing 'retry_delay' or 'max_request_time'", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, buffer, sizeof(buffer)), @@ -3246,17 +3358,6 @@ REQUEST *received_proxy_response(RADIUS_PACKET *packet) } #endif - /* - * There's no incoming request, so it's a proxied packet - * we originated. - */ - if (!request->packet) { - received_response_to_ping(request); - request->proxy_reply = NULL; /* caller will free it */ - ev_request_free(&request); - return NULL; - } - request->child_state = REQUEST_QUEUED; request->when = now; request->delay = USEC; @@ -3468,7 +3569,7 @@ int event_new_fd(rad_listen_t *this) } #ifdef WITH_PROXY else { - int count = this->count; + int count; /* * Duplicate code @@ -3550,7 +3651,10 @@ int event_new_fd(rad_listen_t *this) */ if (this->status == RAD_LISTEN_STATUS_CLOSED) { int count = this->count; + +#ifdef WITH_DETAIL rad_assert(this->type != RAD_LISTEN_DETAIL); +#endif #ifdef WITH_PROXY /* @@ -3673,13 +3777,14 @@ static void handle_signal_self(int flag) time_t when; static time_t last_hup = 0; - radlog(L_INFO, "Received HUP signal."); - when = time(NULL); if ((int) (when - last_hup) < 5) { radlog(L_INFO, "Ignoring HUP (less than 5s since last one)"); return; } + + radlog(L_INFO, "Received HUP signal."); + last_hup = when; fr_event_loop_exit(el, 0x80); @@ -3825,45 +3930,44 @@ static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd, xel = xel; - if (listener->fd < 0) rad_panic("Socket was closed on us!"); + if ( +#ifdef WITH_DETAIL + (listener->type != RAD_LISTEN_DETAIL) && +#endif + (listener->fd < 0)) { + char buffer[256]; + + listener->print(listener, buffer, sizeof(buffer)); + radlog(L_ERR, "FATAL: Asked to read from closed socket: %s", + buffer); + + rad_panic("Socket was closed on us!"); + _exit(1); + } if (!listener->recv(listener, &fun, &request)) return; - if (!thread_pool_addrequest(request, fun)) { - request->child_state = REQUEST_DONE; - } -} + rad_assert(fun != NULL); + rad_assert(request != NULL); + thread_pool_addrequest(request, fun); +} +#ifdef WITH_DETAIL /* * This function is called periodically to see if this detail * file is available for reading. */ static void event_poll_detail(void *ctx) { - int rcode, delay; - RAD_REQUEST_FUNP fun; - REQUEST *request; + int delay; rad_listen_t *this = ctx; struct timeval when; listen_detail_t *detail = this->data; rad_assert(this->type == RAD_LISTEN_DETAIL); - /* - * Try to read something. - * - * FIXME: This does poll AND receive. - */ - rcode = this->recv(this, &fun, &request); - if (rcode != 0) { - rad_assert(fun != NULL); - rad_assert(request != NULL); - - if (!thread_pool_addrequest(request, fun)) { - request->child_state = REQUEST_DONE; - } - } + event_socket_handler(el, this->fd, this); fr_event_now(el, &now); when = now; @@ -3881,7 +3985,7 @@ static void event_poll_detail(void *ctx) exit(1); } } - +#endif static void event_status(struct timeval *wake) { @@ -3964,12 +4068,6 @@ int radius_event_init(CONF_SECTION *cs, int spawn_flag) } #endif - /* - * Just before we spawn the child threads, force the log - * subsystem to re-open the log file for every write. - */ - if (spawn_flag) force_log_reopen(); - #ifdef HAVE_PTHREAD_H #ifndef __MINGW32__ NO_SUCH_CHILD_PID = (pthread_t ) (0); @@ -3996,6 +4094,10 @@ int radius_event_init(CONF_SECTION *cs, int spawn_flag) if (check_config) { DEBUG("%s: #### Skipping IP addresses and Ports ####", mainconfig.name); + if (listen_init(cs, &head) < 0) { + fflush(NULL); + exit(1); + } return 1; }