/* * Check_pings_list() * * inputs - pointer to list to check * output - NONE * side effects - */ static void check_pings_list(dlink_list *list) { char scratch[32]; /* way too generous but... */ struct Client *client_p; /* current local client_p being examined */ int ping = 0; /* ping time value from client */ dlink_node *ptr, *next_ptr; for (ptr = list->head; ptr; ptr = next_ptr) { next_ptr = ptr->next; client_p = ptr->data; /* ** Note: No need to notify opers here. It's ** already done when "FLAGS_DEADSOCKET" is set. */ if (client_p->flags & FLAGS_DEADSOCKET) { /* Ignore it, its been exited already */ continue; } if (IsPerson(client_p)) { if(!IsExemptKline(client_p) && GlobalSetOptions.idletime && !IsOper(client_p) && !IsIdlelined(client_p) && ((CurrentTime - client_p->user->last) > GlobalSetOptions.idletime)) { struct ConfItem *aconf; aconf = make_conf(); aconf->status = CONF_KILL; DupString(aconf->host, client_p->host); DupString(aconf->passwd, "idle exceeder"); DupString(aconf->name, client_p->username); aconf->port = 0; aconf->hold = CurrentTime + 60; add_temp_kline(aconf); sendto_realops_flags(FLAGS_ALL, L_ALL, "Idle time limit exceeded for %s - temp k-lining", get_client_name(client_p, HIDE_IP)); (void)exit_client(client_p, client_p, &me, aconf->passwd); continue; } } if (!IsRegistered(client_p)) ping = CONNECTTIMEOUT; else ping = get_client_ping(client_p); if (ping < (CurrentTime - client_p->lasttime)) { /* * If the client/server hasnt talked to us in 2*ping seconds * and it has a ping time, then close its connection. */ if (((CurrentTime - client_p->lasttime) >= (2 * ping) && (client_p->flags & FLAGS_PINGSENT))) { if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p)) { sendto_realops_flags(FLAGS_ALL, L_ADMIN, "No response from %s, closing link", get_client_name(client_p, HIDE_IP)); sendto_realops_flags(FLAGS_ALL, L_OPER, "No response from %s, closing link", get_client_name(client_p, MASK_IP)); ilog(L_NOTICE, "No response from %s, closing link", get_client_name(client_p, HIDE_IP)); } (void)ircsprintf(scratch, "Ping timeout: %d seconds", (int)(CurrentTime - client_p->lasttime)); (void)exit_client(client_p, client_p, &me, scratch); continue; } else if ((client_p->flags & FLAGS_PINGSENT) == 0) { /* * if we havent PINGed the connection and we havent * heard from it in a while, PING it to make sure * it is still alive. */ client_p->flags |= FLAGS_PINGSENT; /* not nice but does the job */ client_p->lasttime = CurrentTime - ping; sendto_one(client_p, "PING :%s", me.name); } } /* ping_timeout: */ } }
static time_t check_pings(time_t currenttime) { register aClient *cptr; /* current local cptr being examined */ aConfItem *aconf = (aConfItem *)NULL; int ping = 0; /* ping time value from client */ int i; /* used to index through fd/cptr's */ time_t oldest = 0; /* next ping time */ time_t timeout; /* found necessary ping time */ char *reason; /* pointer to reason string */ int die_index=0; /* index into list */ char ping_time_out_buffer[64]; /* blech that should be a define */ /* of dying clients */ dying_clients[0] = (aClient *)NULL; /* mark first one empty */ /* * I re-wrote the way klines are handled. Instead of rescanning * the local[] array and calling exit_client() right away, I * mark the client thats dying by placing a pointer to its aClient * into dying_clients[]. When I have examined all in local[], * I then examine the dying_clients[] for aClient's to exit. * This saves the rescan on k-lines, also greatly simplifies the code, * * Jan 28, 1998 * -Dianora */ for (i = 0; i <= highest_fd; i++) { if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr)) continue; /* and go examine next fd/cptr */ /* ** Note: No need to notify opers here. It's ** already done when "FLAGS_DEADSOCKET" is set. */ if (cptr->flags & FLAGS_DEADSOCKET) { /* N.B. EVERY single time dying_clients[] is set * it must be followed by an immediate continue, * to prevent this cptr from being marked again for exit. * If you don't, you could cause exit_client() to be called twice * for the same cptr. i.e. bad news * -Dianora */ dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = ((cptr->flags & FLAGS_SENDQEX) ? "SendQ exceeded" : "Dead socket"); dying_clients[die_index] = (aClient *)NULL; continue; /* and go examine next fd/cptr */ } if (rehashed) { if(dline_in_progress) { if(IsPerson(cptr)) { if( (aconf = find_dkill(cptr)) ) /* if there is a returned aConfItem then kill it */ { sendto_ops("D-line active for %s", get_client_name(cptr, FALSE)); dying_clients[die_index] = cptr; #ifdef KLINE_WITH_REASON reason = aconf->passwd ? aconf->passwd : "D-lined"; dying_clients_reason[die_index++] = reason; #else dying_clients_reason[die_index++] = "D-lined"; #endif dying_clients[die_index] = (aClient *)NULL; sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name, cptr->name, reason); continue; /* and go examine next fd/cptr */ } } } else { if(IsPerson(cptr)) { #ifdef GLINES if( (aconf = find_gkill(cptr)) ) { sendto_ops("G-line active for %s", get_client_name(cptr, FALSE)); dying_clients[die_index] = cptr; #ifdef KLINE_WITH_REASON reason = aconf->passwd ? aconf->passwd : "G-lined"; dying_clients_reason[die_index++] = reason; #else dying_clients_reason[die_index++] = "G-lined"; #endif dying_clients[die_index] = (aClient *)NULL; sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name, cptr->name, reason); continue; /* and go examine next fd/cptr */ } else #endif if((aconf = find_kill(cptr))) /* if there is a returned aConfItem.. then kill it */ { sendto_ops("K-line active for %s", get_client_name(cptr, FALSE)); dying_clients[die_index] = cptr; #ifdef KLINE_WITH_REASON #ifdef K_COMMENT_ONLY reason = aconf->passwd ? aconf->passwd : "K-lined"; #else reason = (BadPtr(aconf->passwd) || !is_comment(aconf->passwd)) ? "K-lined" : aconf->passwd; #endif dying_clients_reason[die_index++] = reason; #else dying_clients_reason[die_index++] = "K-lined"; #endif dying_clients[die_index] = (aClient *)NULL; sendto_one(cptr, err_str(ERR_YOUREBANNEDCREEP), me.name, cptr->name, reason); continue; /* and go examine next fd/cptr */ } } } } #ifdef IDLE_CHECK if (IsPerson(cptr)) { if( !IsElined(cptr) && ((timeofday - cptr->user->last) > idle_time)) { aConfItem *aconf; dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = "idle exceeder"; dying_clients[die_index] = (aClient *)NULL; aconf = make_conf(); aconf->status = CONF_KILL; DupString(aconf->host, cptr->user->host); DupString(aconf->passwd, "idle exceeder" ); DupString(aconf->name, cptr->user->username); aconf->port = 0; aconf->hold = timeofday + 60; add_temp_kline(aconf); sendto_ops("Idle exceeder %s temp k-lining", get_client_name(cptr,FALSE)); continue; /* and go examine next fd/cptr */ } } #endif #ifdef REJECT_HOLD if (IsRejectHeld(cptr)) { if( timeofday > (cptr->firsttime + REJECT_HOLD_TIME) ) { dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = "reject held client"; dying_clients[die_index] = (aClient *)NULL; continue; /* and go examine next fd/cptr */ } } #endif #if defined(R_LINES) && defined(R_LINES_OFTEN) /* * this is used for KILL lines with time restrictions * on them - send a message to the user being killed * first. * *** Moved up above -taner *** * * Moved here, no more rflag -Dianora */ if (IsPerson(cptr) && find_restrict(cptr)) { sendto_ops("Restricting %s, closing link.", get_client_name(cptr,FALSE)); dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = "you have been R-lined"; dying_clients[die_index] = (aClient *)NULL; continue; /* and go examine next fd/cptr */ } #endif if (!IsRegistered(cptr)) ping = CONNECTTIMEOUT; else ping = get_client_ping(cptr); /* * Ok, so goto's are ugly and can be avoided here but this code * is already indented enough so I think its justified. -avalon */ /* if (!rflag && (ping >= currenttime - cptr->lasttime)) goto ping_timeout; */ /* * *sigh* I think not -Dianora */ if (ping < (currenttime - cptr->lasttime)) { /* * If the server hasnt talked to us in 2*ping seconds * and it has a ping time, then close its connection. * If the client is a user and a KILL line was found * to be active, close this connection too. */ if (((currenttime - cptr->lasttime) >= (2 * ping) && (cptr->flags & FLAGS_PINGSENT)) || ((!IsRegistered(cptr) && (currenttime - cptr->since) >= ping))) { if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr))) { if (cptr->authfd >= 0) { (void)close(cptr->authfd); cptr->authfd = -1; cptr->count = 0; *cptr->buffer = '\0'; } #ifdef SHOW_HEADERS if (DoingDNS(cptr)) send(cptr->fd, REPORT_FAIL_DNS, R_fail_dns, 0); else send(cptr->fd, REPORT_FAIL_ID, R_fail_id, 0); #endif Debug((DEBUG_NOTICE,"DNS/AUTH timeout %s", get_client_name(cptr,TRUE))); del_queries((char *)cptr); ClearAuth(cptr); ClearDNS(cptr); SetAccess(cptr); cptr->since = currenttime; continue; } if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr)) { sendto_ops("No response from %s, closing link", get_client_name(cptr, FALSE)); } /* * this is used for KILL lines with time restrictions * on them - send a messgae to the user being killed * first. * *** Moved up above -taner *** */ cptr->flags2 |= FLAGS2_PING_TIMEOUT; dying_clients[die_index++] = cptr; /* the reason is taken care of at exit time */ /* dying_clients_reason[die_index++] = "Ping timeout"; */ dying_clients[die_index] = (aClient *)NULL; /* * need to start loop over because the close can * affect the ordering of the local[] array.- avalon * ** Not if you do it right - Dianora */ continue; } else if ((cptr->flags & FLAGS_PINGSENT) == 0) { /* * if we havent PINGed the connection and we havent * heard from it in a while, PING it to make sure * it is still alive. */ cptr->flags |= FLAGS_PINGSENT; /* not nice but does the job */ cptr->lasttime = currenttime - ping; sendto_one(cptr, "PING :%s", me.name); } } /* ping_timeout: */ timeout = cptr->lasttime + ping; while (timeout <= currenttime) timeout += ping; if (timeout < oldest || !oldest) oldest = timeout; /* * Check UNKNOWN connections - if they have been in this state * for > 100s, close them. */ if (IsUnknown(cptr)) { if (cptr->firsttime ? ((timeofday - cptr->firsttime) > 100) : 0) { dying_clients[die_index] = cptr; dying_clients_reason[die_index++] = "Connection Timed Out"; dying_clients[die_index] = (aClient *)NULL; continue; } } } /* Now exit clients marked for exit above. * it doesn't matter if local[] gets re-arranged now * * -Dianora */ for(die_index = 0; (cptr = dying_clients[die_index]); die_index++) { if(cptr->flags2 & FLAGS2_PING_TIMEOUT) { (void)ircsprintf(ping_time_out_buffer, "Ping timeout: %d seconds", currenttime - cptr->lasttime); (void)exit_client(cptr, cptr, &me, ping_time_out_buffer ); } else (void)exit_client(cptr, cptr, &me, dying_clients_reason[die_index]); } rehashed = 0; dline_in_progress = 0; if (!oldest || oldest < currenttime) oldest = currenttime + PINGFREQUENCY; Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d", myctime(oldest), ping, oldest, currenttime)); return (oldest); }