📄 event.c
字号:
inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), request->proxy->dst_port); wait_for_proxy_id_to_expire(request);}static void received_response_to_ping(REQUEST *request){ home_server *home = request->home_server; char buffer[128]; home->num_received_pings++; DEBUG2("Received response to status check %d (%d in current sequence)", request->number, home->num_received_pings); if (home->num_received_pings < home->num_pings_to_alive) { wait_for_proxy_id_to_expire(request); return; } DEBUG2("Marking home server %s port %d alive", inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), request->proxy->dst_port); if (!fr_event_delete(el, &home->ev)) { DEBUG2("Hmm... no event for home server, WTF?"); } if (!fr_event_delete(el, &request->ev)) { DEBUG2("Hmm... no event for request, WTF?"); } wait_for_proxy_id_to_expire(request); home->state = HOME_STATE_ALIVE; home->currently_outstanding = 0;}static void ping_home_server(void *ctx){ uint32_t jitter; home_server *home = ctx; REQUEST *request; VALUE_PAIR *vp; if (home->state == HOME_STATE_ALIVE) { radlog(L_INFO, "Suspicious proxy state... continuing"); return; } request = request_alloc(); request->number = request_num_counter++; request->proxy = rad_alloc(1); rad_assert(request->proxy != NULL); fr_event_now(el, &request->when); home->when = request->when; if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) { request->proxy->code = PW_STATUS_SERVER; radius_pairmake(request, &request->proxy->vps, "Message-Authenticator", "0x00", T_OP_SET); } else if (home->type == HOME_TYPE_AUTH) { request->proxy->code = PW_AUTHENTICATION_REQUEST; radius_pairmake(request, &request->proxy->vps, "User-Name", home->ping_user_name, T_OP_SET); radius_pairmake(request, &request->proxy->vps, "User-Password", home->ping_user_password, T_OP_SET); radius_pairmake(request, &request->proxy->vps, "Service-Type", "Authenticate-Only", T_OP_SET); radius_pairmake(request, &request->proxy->vps, "Message-Authenticator", "0x00", T_OP_SET); } else { request->proxy->code = PW_ACCOUNTING_REQUEST; radius_pairmake(request, &request->proxy->vps, "User-Name", home->ping_user_name, T_OP_SET); radius_pairmake(request, &request->proxy->vps, "Acct-Status-Type", "Stop", T_OP_SET); radius_pairmake(request, &request->proxy->vps, "Acct-Session-Id", "00000000", T_OP_SET); vp = radius_pairmake(request, &request->proxy->vps, "Event-Timestamp", "0", T_OP_SET); vp->vp_date = now.tv_sec; } radius_pairmake(request, &request->proxy->vps, "NAS-Identifier", "Status Check. Are you alive?", T_OP_SET); request->proxy->dst_ipaddr = home->ipaddr; request->proxy->dst_port = home->port; request->home_server = home; rad_assert(request->proxy_listener == NULL); if (!insert_into_proxy_hash(request)) { DEBUG2("ERROR: Failed inserting status check %d into proxy hash. Discarding it.", request->number); request_free(&request); return; } rad_assert(request->proxy_listener != NULL); request->proxy_listener->send(request->proxy_listener, request); request->next_callback = NULL; request->child_state = REQUEST_PROXIED; request->when.tv_sec += home->ping_timeout;; INSERT_EVENT(no_response_to_ping, request); /* * Add +/- 2s of jitter, as suggested in RFC 3539 * and in the Issues and Fixes draft. */ home->when.tv_sec += home->ping_interval - 2; jitter = fr_rand(); jitter ^= (jitter >> 10); jitter &= ((1 << 23) - 1); /* 22 bits of 1 */ tv_add(&home->when, jitter); INSERT_EVENT(ping_home_server, home);}static void check_for_zombie_home_server(REQUEST *request){ home_server *home; struct timeval when; char buffer[128]; home = request->home_server; if (home->state != HOME_STATE_ZOMBIE) return; when = home->zombie_period_start; when.tv_sec += home->zombie_period; fr_event_now(el, &now); if (timercmp(&now, &when, <)) { return; } /* * It's been a zombie for too long, mark it as * dead. */ DEBUG2("FAILURE: Marking home server %s port %d as dead.", inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), request->proxy->dst_port); home->state = HOME_STATE_IS_DEAD; home->num_received_pings = 0; home->when = request->when; if (home->ping_check != HOME_PING_CHECK_NONE) { rad_assert((home->ping_check == HOME_PING_CHECK_STATUS_SERVER) || (home->ping_user_name != NULL)); home->when.tv_sec += home->ping_interval; INSERT_EVENT(ping_home_server, home); } else { home->when.tv_sec += home->revive_interval; INSERT_EVENT(revive_home_server, home); }}static int setup_post_proxy_fail(REQUEST *request){ DICT_VALUE *dval = NULL; VALUE_PAIR *vp; if (request->packet->code == PW_AUTHENTICATION_REQUEST) { dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Authentication"); } else if (request->packet->code == PW_ACCOUNTING_REQUEST) { dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Accounting"); } else { return 0; } if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail"); if (!dval) { pairdelete(&request->config_items, PW_POST_PROXY_TYPE); return 0; } vp = pairfind(request->config_items, PW_POST_PROXY_TYPE); if (!vp) vp = radius_paircreate(request, &request->config_items, PW_POST_PROXY_TYPE, PW_TYPE_INTEGER); vp->vp_integer = dval->value; rad_assert(request->proxy_reply == NULL); return 1;}static int null_handler(UNUSED REQUEST *request){ return 0;}static void post_proxy_fail_handler(REQUEST *request){ /* * A proper time is required for wait_a_bit. */ request->delay = USEC / 10; gettimeofday(&now, NULL); /* * Not set up to run Post-Proxy-Type = Fail. * * Mark the request as still running, and figure out what * to do next. */ if (!setup_post_proxy_fail(request)) { request->child_state = REQUEST_RUNNING; request_post_handler(request); } else { /* * Re-queue the request. */ request->child_state = REQUEST_QUEUED; /* * There is a post-proxy-type of fail. We run * the request through the pre/post proxy * handlers, just like it was a real proxied * request. However, we set the per-request * handler to NULL, as we don't want to do * anything else. * * Note that when we're not threaded, this will * process the request even if it's greater than * max_request_time. That's not fatal. */ request->priority = 0; rad_assert(request->proxy != NULL); thread_pool_addrequest(request, null_handler); } /* * MAY free the request if we're over max_request_time, * AND we're not in threaded mode! * * Note that we call this ONLY if we're threaded, as * if we're NOT threaded, request_post_handler() calls * wait_a_bit(), which means that "request" may not * exist any more... */ if (have_children) wait_a_bit(request);}/* maybe check this against wait_for_proxy_id_to_expire? */static void no_response_to_proxied_request(void *ctx){ REQUEST *request = ctx; home_server *home; char buffer[128]; rad_assert(request->magic == REQUEST_MAGIC); rad_assert(request->child_state == REQUEST_PROXIED); radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d", request->number, inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), request->proxy->dst_port); check_for_zombie_home_server(request); home = request->home_server; post_proxy_fail_handler(request); /* * Don't touch request due to race conditions */ if (home->state == HOME_STATE_IS_DEAD) { rad_assert(home->ev != NULL); /* or it will never wake up */ return; } /* * Enable the zombie period when we notice that the home * server hasn't responded. We also back-date the start * of the zombie period to when the proxied request was * sent. */ if (home->state == HOME_STATE_ALIVE) { DEBUG2("WARNING: 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); home->state = HOME_STATE_ZOMBIE; home->zombie_period_start = now; home->zombie_period_start.tv_sec -= home->response_window; return; }}static void wait_a_bit(void *ctx){ struct timeval when; REQUEST *request = ctx; fr_event_callback_t callback = NULL; rad_assert(request->magic == REQUEST_MAGIC); switch (request->child_state) { case REQUEST_QUEUED: case REQUEST_RUNNING: when = request->received; when.tv_sec += request->root->max_request_time; /* * Normally called from the event loop with the * proper event loop time. Otherwise, called from * post proxy fail handler, which sets "now", and * this call won't re-set it, because we're not * in the event loop. */ fr_event_now(el, &now); /* * Request still has more time. Continue * waiting. */ if (timercmp(&now, &when, <) || ((request->listener->type == RAD_LISTEN_DETAIL) && (request->child_state == REQUEST_QUEUED))) { if (request->delay < (USEC / 10)) { request->delay = USEC / 10; } request->delay += request->delay >> 1; /* * Cap wait at some sane value for detail * files. */ if ((request->listener->type == RAD_LISTEN_DETAIL) && (request->delay > (request->root->max_request_time * USEC))) { request->delay = request->root->max_request_time * USEC; } request->when = now; tv_add(&request->when, request->delay); callback = wait_a_bit; break; } /* * A child thread MAY still be running on the * request. Ask the thread to stop working on * the request. */ if (have_children) { /* FIXME: kill unresponsive children? */ /* * Print this error message ONLY if * there's a child currently processing * the request. As we don't have thread * locks here, there may be race * conditions on this check. But it's * just an error message, so that's OK. */ if (request->child_pid != NO_SUCH_CHILD_PID) { radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d, in module %s component %s", (unsigned long)request->child_pid, request->number, request->module ? request->module : "<server core>", request->component ? request->component : "<server core>"); } request->master_state = REQUEST_STOP_PROCESSING; request->delay = USEC / 4; tv_add(&request->when, request->delay); callback = wait_for_child_to_die; break; } /* * Else there are no child threads. 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: request->child_pid = NO_SUCH_CHILD_PID; snmp_inc_counters(request); cleanup_delay(request); return; case REQUEST_REJECT_DELAY: case REQUEST_CLEANUP_DELAY: request->child_pid = NO_SUCH_CHILD_PID; snmp_inc_counters(request); case REQUEST_PROXIED: rad_assert(request->next_callback != NULL); rad_assert(request->next_callback != wait_a_bit); request->when = request->next_when; callback = request->next_callback; request->next_callback = NULL; break; default: rad_panic("Internal sanity check failure"); return; } /* * Something major went wrong. Discard the request, and * keep running. * * FIXME: No idea why this happens or how to fix it... * It seems to happen *only* when requests are proxied, * and where the home server doesn't respond. So it looks * like a race condition above, but it happens in debug * mode, with no threads... */ if (!callback) { DEBUG("WARNING: Internal sanity check failed in event handler for request %d: Discarding the request!", request->number); fr_event_delete(el, &request->ev); remove_from_proxy_hash(request); remove_from_request_hash(request); request_free(&request); return; } INSERT_EVENT(callback, request);}static int request_pre_handler(REQUEST *request){ int rcode; rad_assert(request->magic == REQUEST_MAGIC); rad_assert(request->packet != NULL); request->child_state = REQUEST_RUNNING; /* * Don't decode the packet if it's an internal "fake" * request. Instead, just return so that the caller can * process it. */ if (request->packet->dst_port == 0) { request->username = pairfind(request->packet->vps, PW_USER_NAME); request->password = pairfind(request->packet->vps, PW_USER_PASSWORD); return 1; } /* * Put the decoded packet into it's proper place. */ if (request->proxy_reply != NULL) { rcode = request->proxy_listener->decode(request->proxy_listener, request); } else if (request->packet->vps == NULL) { rcode = request->listener->decode(request->listener, request); } else { rcode = 0; } if (rcode < 0) { radlog(L_ERR, "%s Dropping packet without response.", librad_errstr); request->child_state = REQUEST_DONE; return 0; } if (!request->proxy) { request->username = pairfind(request->packet->vps, PW_USER_NAME); } else { int post_proxy_type = 0; VALUE_PAIR *vp; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -