/* send_linebuf() * * inputs - client to send to, linebuf to attach * outputs - * side effects - linebuf is attached to client */ static int _send_linebuf(struct Client *to, buf_head_t *linebuf) { if(IsMe(to)) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Trying to send message to myself!"); return 0; } if(!MyConnect(to) || IsIOError(to)) return 0; if(rb_linebuf_len(&to->localClient->buf_sendq) > get_sendq(to)) { if(IsServer(to)) { sendto_realops_snomask(SNO_GENERAL, L_ALL, "Max SendQ limit exceeded for %s: %u > %lu", to->name, rb_linebuf_len(&to->localClient->buf_sendq), get_sendq(to)); ilog(L_SERVER, "Max SendQ limit exceeded for %s: %u > %lu", log_client_name(to, SHOW_IP), rb_linebuf_len(&to->localClient->buf_sendq), get_sendq(to)); } dead_link(to, 1); return -1; } else { /* just attach the linebuf to the sendq instead of * generating a new one */ rb_linebuf_attach(&to->localClient->buf_sendq, linebuf); } /* ** Update statistics. The following is slightly incorrect ** because it counts messages even if queued, but bytes ** only really sent. Queued bytes get updated in SendQueued. */ to->localClient->sendM += 1; me.localClient->sendM += 1; if(rb_linebuf_len(&to->localClient->buf_sendq) > 0) send_queued(to); return 0; }
/* * safelist_sendq_exceeded() * * inputs - pointer to client that needs checking * outputs - 1 if a client has exceeded the reserved * sendq limit, 0 if not * side effects - none * * When safelisting, we only use half of the SendQ at any * given time. */ static int safelist_sendq_exceeded(struct Client *client_p) { if (rb_linebuf_len(&client_p->localClient->buf_sendq) > (get_sendq(client_p) / 2)) return YES; else return NO; }
/* send_queued_write() * * inputs - fd to have queue sent, client we're sending to * outputs - contents of queue * side effects - write is rescheduled if queue isnt emptied */ void send_queued(struct Client *to) { int retlen; #ifdef USE_IODEBUG_HOOKS hook_data_int hd; #endif rb_fde_t *F = to->localClient->F; if (!F) return; /* cant write anything to a dead socket. */ if(IsIOError(to)) return; /* Something wants us to not send anything currently */ /* if(IsCork(to)) return; */ /* try to flush later when the write event resets this */ if(IsFlush(to)) return; #ifdef USE_IODEBUG_HOOKS hd.client = to; if(to->localClient->buf_sendq.list.head) hd.arg1 = ((buf_line_t *) to->localClient->buf_sendq.list.head->data)->buf + to->localClient->buf_sendq.writeofs; #endif if(rb_linebuf_len(&to->localClient->buf_sendq)) { while ((retlen = rb_linebuf_flush(F, &to->localClient->buf_sendq)) > 0) { /* We have some data written .. update counters */ #ifdef USE_IODEBUG_HOOKS hd.arg2 = retlen; call_hook(h_iosend_id, &hd); if(to->localClient->buf_sendq.list.head) hd.arg1 = ((buf_line_t *) to->localClient->buf_sendq.list.head-> data)->buf + to->localClient->buf_sendq.writeofs; #endif ClearFlush(to); to->localClient->sendB += retlen; me.localClient->sendB += retlen; if(to->localClient->sendB > 1023) { to->localClient->sendK += (to->localClient->sendB >> 10); to->localClient->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */ } else if(me.localClient->sendB > 1023) { me.localClient->sendK += (me.localClient->sendB >> 10); me.localClient->sendB &= 0x03ff; }
static void rb_helper_write_sendq(rb_fde_t *F, void *helper_ptr) { rb_helper *helper = helper_ptr; int retlen; if(rb_linebuf_len(&helper->sendq) > 0) { while((retlen = rb_linebuf_flush(F, &helper->sendq)) > 0) ; if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) { rb_helper_restart(helper); return; } } if(rb_linebuf_len(&helper->sendq) > 0) rb_setselect(helper->ofd, RB_SELECT_WRITE, rb_helper_write_sendq, helper); }
char *get_client_sendq(const struct Client *client) { static char buf[EXT_BUFSIZE + sizeof(CRLF)]; if (rb_linebuf_len(&client->localClient->buf_sendq)) { int ret; memset(buf, 0, sizeof(buf)); ret = rb_linebuf_get(&client->localClient->buf_sendq, buf, sizeof(buf), 0, 1); if (ok(ret > 0, MSG)) { return buf; } else { return "<get_client_sendq error>"; } } return ""; }
/* send_queued_write() * * inputs - fd to have queue sent, client we're sending to * outputs - contents of queue * side effects - write is rescheduled if queue isnt emptied */ void send_queued(struct Client *to) { int retlen; rb_fde_t *F = to->localClient->F; if (!F) return; /* cant write anything to a dead socket. */ if(IsIOError(to)) return; /* try to flush later when the write event resets this */ if(IsFlush(to)) return; if(rb_linebuf_len(&to->localClient->buf_sendq)) { while ((retlen = rb_linebuf_flush(F, &to->localClient->buf_sendq)) > 0) { /* We have some data written .. update counters */ ClearFlush(to); to->localClient->sendB += retlen; me.localClient->sendB += retlen; if(to->localClient->sendB > 1023) { to->localClient->sendK += (to->localClient->sendB >> 10); to->localClient->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */ } else if(me.localClient->sendB > 1023) { me.localClient->sendK += (me.localClient->sendB >> 10); me.localClient->sendB &= 0x03ff; }
/* ** m_whowas ** parv[1] = nickname queried */ static int m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) { struct Whowas *temp; int cur = 0; int max = -1, found = 0; char *p; const char *nick; char tbuf[26]; long sendq_limit; static time_t last_used = 0L; if(MyClient(source_p) && !IsOper(source_p)) { if(last_used + (parc > 3 ? ConfigFileEntry.pace_wait : ConfigFileEntry.pace_wait_simple ) > rb_current_time()) { sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, source_p->name, "WHOWAS"); sendto_one(source_p, form_str(RPL_ENDOFWHOWAS), me.name, source_p->name, parv[1]); return 0; } else last_used = rb_current_time(); } if(parc > 2) max = atoi(parv[2]); if(parc > 3) if(hunt_server(client_p, source_p, ":%s WHOWAS %s %s :%s", 3, parc, parv)) return 0; if(!MyClient(source_p) && (max <= 0 || max > 20)) max = 20; if((p = strchr(parv[1], ','))) *p = '\0'; nick = parv[1]; sendq_limit = get_sendq(client_p) * 9 / 10; temp = WHOWASHASH[hash_whowas_name(nick)]; found = 0; for (; temp; temp = temp->next) { if(!irccmp(nick, temp->name)) { if(cur > 0 && rb_linebuf_len(&client_p->localClient->buf_sendq) > sendq_limit) { sendto_one(source_p, form_str(ERR_TOOMANYMATCHES), me.name, source_p->name, "WHOWAS"); break; } sendto_one(source_p, form_str(RPL_WHOWASUSER), me.name, source_p->name, temp->name, temp->username, temp->hostname, temp->realname); if (!EmptyString(temp->sockhost) && strcmp(temp->sockhost, "0") && show_ip_whowas(temp, source_p)) #if 0 sendto_one(source_p, form_str(RPL_WHOWASREAL), me.name, source_p->name, temp->name, "<untracked>", temp->sockhost); #else sendto_one_numeric(source_p, RPL_WHOISACTUALLY, form_str(RPL_WHOISACTUALLY), temp->name, temp->sockhost); #endif if (!EmptyString(temp->suser)) sendto_one_numeric(source_p, RPL_WHOISLOGGEDIN, "%s %s :was logged in as", temp->name, temp->suser); sendto_one_numeric(source_p, RPL_WHOISSERVER, form_str(RPL_WHOISSERVER), temp->name, temp->servername, rb_ctime(temp->logoff, tbuf, sizeof(tbuf))); cur++; found++; } if(max > 0 && cur >= max) break; } if(!found) sendto_one(source_p, form_str(ERR_WASNOSUCHNICK), me.name, source_p->name, nick); sendto_one(source_p, form_str(RPL_ENDOFWHOWAS), me.name, source_p->name, parv[1]); return 0; }