/** Attempt to send data queued for a client. * @param[in] to Client to send data to. */ void send_queued(struct Client *to) { assert(0 != to); assert(0 != cli_local(to)); if (IsBlocked(to) || !can_send(to)) return; /* Don't bother */ while (MsgQLength(&(cli_sendQ(to))) > 0) { unsigned int len; if ((len = deliver_it(to, &(cli_sendQ(to))))) { msgq_delete(&(cli_sendQ(to)), len); cli_lastsq(to) = MsgQLength(&(cli_sendQ(to))) / 1024; if (IsBlocked(to)) { update_write(to); return; } } else { if (IsDead(to)) { char tmp[512]; sprintf(tmp,"Write error: %s", ((cli_sslerror(to)) ? (cli_sslerror(to)) : ((strerror(cli_error(to))) ? (strerror(cli_error(to))) : "Unknown error")) ); dead_link(to, tmp); } return; } } /* Ok, sendq is now empty... */ client_drop_sendq(cli_connect(to)); update_write(to); }
/* 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(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", get_server_name(to, HIDE_IP), 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), linebuf_len(&to->localClient->buf_sendq), get_sendq(to)); } if(IsClient(to)) to->flags |= FLAGS_SENDQEX; dead_link(to); return -1; } else { /* just attach the linebuf to the sendq instead of * generating a new one */ 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(linebuf_len(&to->localClient->buf_sendq) > 0) send_queued_write(to->localClient->fd, to); return 0; }
/** Try to send a buffer to a client, queueing it if needed. * @param[in,out] to Client to send message to. * @param[in] buf Message to send. * @param[in] prio If non-zero, send as high priority. */ void send_buffer(struct Client* to, struct MsgBuf* buf, int prio) { assert(0 != to); assert(0 != buf); if (cli_from(to)) to = cli_from(to); if (!can_send(to)) /* * This socket has already been marked as dead */ return; if (MsgQLength(&(cli_sendQ(to))) > get_sendq(to)) { if (IsServer(to)) sendto_opmask(0, SNO_OLDSNO, "Max SendQ limit exceeded for %C: %zu > %zu", to, MsgQLength(&(cli_sendQ(to))), get_sendq(to)); dead_link(to, "Max sendQ exceeded"); return; } Debug((DEBUG_SEND, "Sending [%p] to %s", buf, cli_name(to))); #if defined(USE_SSL) if (cli_socket(to).s_ssl) prio = 0; #endif msgq_add(&(cli_sendQ(to)), buf, prio); client_add_sendq(cli_connect(to), &send_queues); update_write(to); /* * 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. */ ++(cli_sendM(to)); ++(cli_sendM(&me)); /* * This little bit is to stop the sendQ from growing too large when * there is no need for it to. Thus we call send_queued() every time * 2k has been added to the queue since the last non-fatal write. * Also stops us from deliberately building a large sendQ and then * trying to flood that link with data (possible during the net * relinking done by servers with a large load). */ if (MsgQLength(&(cli_sendQ(to))) / 1024 > cli_lastsq(to)) send_queued(to); }
/** Close the connection with the highest sendq. * This should be called when we need to free buffer memory. * @param[in] servers_too If non-zero, consider killing servers, too. */ void kill_highest_sendq(int servers_too) { int i; unsigned int highest_sendq = 0; struct Client *highest_client = 0; for (i = HighestFd; i >= 0; i--) { if (!LocalClientArray[i] || (!servers_too && cli_serv(LocalClientArray[i]))) continue; /* skip servers */ /* If this sendq is higher than one we last saw, remember it */ if (MsgQLength(&(cli_sendQ(LocalClientArray[i]))) > highest_sendq) { highest_client = LocalClientArray[i]; highest_sendq = MsgQLength(&(cli_sendQ(highest_client))); } } if (highest_client) dead_link(highest_client, "Buffer allocation error"); }
/* ** send_queued ** This function is called from the main select-loop (or whatever) ** when there is a chance the some output would be possible. This ** attempts to empty the send queue as far as possible... */ int send_queued(aClient *to) { char *msg; int len, rlen, more = 0; aClient *bysptr = NULL; /* ** Once socket is marked dead, we cannot start writing to it, ** even if the error is removed... */ if (IsDead(to)) { /* ** Actually, we should *NEVER* get here--something is ** not working correct if send_queued is called for a ** dead socket... --msa */ return -1; } #ifdef ZIP_LINKS /* ** Here, we must make sure than nothing will be left in to->zip->outbuf ** This buffer needs to be compressed and sent if all the sendQ is sent */ if ((to->flags & FLAGS_ZIP) && to->zip->outcount) { if (DBufLength(&to->sendQ) > 0) more = 1; else { msg = zip_buffer(to, NULL, &len, 1); if (len == -1) return dead_link(to, "fatal error in zip_buffer()"); if (dbuf_put(&to->sendQ, msg, len) < 0) { to->exitc = EXITC_MBUF; return dead_link(to, "Buffer allocation error for %s", get_client_name(to, FALSE)); } } } #endif while (DBufLength(&to->sendQ) > 0 || more) { msg = dbuf_map(&to->sendQ, &len); /* Returns always len > 0 */ if ((rlen = deliver_it(to, msg, len)) < 0) { if ( (IsConnecting(to) || IsHandshake(to)) && to->serv && to->serv->byuid[0]) { bysptr = find_uid(to->serv->byuid, NULL); if (bysptr && !MyConnect(bysptr)) { sendto_one(bysptr, ":%s NOTICE %s :" "Write error (%s) to %s, closing link", ME, bysptr->name, strerror(-rlen), to->name); } } return dead_link(to, "Write error (%s) to %s, closing link", strerror(-rlen), get_client_name(to, FALSE)); } (void)dbuf_delete(&to->sendQ, rlen); to->lastsq = DBufLength(&to->sendQ)/1024; if (rlen < len) /* ..or should I continue until rlen==0? */ break; #ifdef ZIP_LINKS if (DBufLength(&to->sendQ) == 0 && more) { /* ** The sendQ is now empty, compress what's left ** uncompressed and try to send it too */ more = 0; msg = zip_buffer(to, NULL, &len, 1); if (len == -1) return dead_link(to, "fatal error in zip_buffer()"); if (dbuf_put(&to->sendQ, msg, len) < 0) { to->exitc = EXITC_MBUF; return dead_link(to, "Buffer allocation error for %s", get_client_name(to, FALSE)); } } #endif } return (IsDead(to)) ? -1 : 0; }
/* ** send_message ** Internal utility which delivers one message buffer to the ** socket. Takes care of the error handling and buffering, if ** needed. ** if ZIP_LINKS is defined, the message will eventually be compressed, ** anything stored in the sendQ is compressed. ** ** If msg is a null pointer, we are flushing connection */ int send_message(aClient *to, char *msg, int len) { int i; Debug((DEBUG_SEND,"Sending %s %d [%s] ", to->name, to->fd, msg)); if (to->from) to = to->from; if (to->fd < 0) { Debug((DEBUG_ERROR, "Local socket %s with negative fd... AARGH!", to->name)); } if (IsMe(to)) { sendto_flag(SCH_ERROR, "Trying to send to myself! [%s]", msg); return 0; } if (IsDead(to)) return 0; /* This socket has already been marked as dead */ if (DBufLength(&to->sendQ) > (i=get_sendq(to, CBurst(to)))) { to->exitc = EXITC_SENDQ; if (IsService(to) || IsServer(to)) { return dead_link(to, "Max SendQ limit exceeded for %s: %d > %d", get_client_name(to, FALSE), DBufLength(&to->sendQ), i); } return dead_link(to, "Max Sendq exceeded"); } # ifdef ZIP_LINKS /* ** data is first stored in to->zip->outbuf until ** it's big enough to be compressed and stored in the sendq. ** send_queued is then responsible to never let the sendQ ** be empty and to->zip->outbuf not empty. */ if (to->flags & FLAGS_ZIP) msg = zip_buffer(to, msg, &len, 0); # endif /* ZIP_LINKS */ tryagain: if (len && (i = dbuf_put(&to->sendQ, msg, len)) < 0) { if (i == -2 /* Poolsize was exceeded. */ #ifdef POOLSIZE_LIMITED /* ** Defining this retains old ircd behaviour (will ** allow client quit with buffer allocation error ** as a result of poolsize starvation). As it may ** happen to all clients on a big channel without ** their fault, I think this is not right. ** In the long run it should not matter (poolsize ** or memory usage-wise), because if client lacks ** the poolsize, the poolsize is too small anyway ** and next netburst would probably make it grow. ** IMO increasing poolsize with no limits is good ** for clients -- hence this is not defined. --B. */ && CBurst(to) #endif ) { /* Anyway, 10% increase. */ poolsize *= 1.1; sendto_flag(SCH_NOTICE, "New poolsize %u. (reached)", poolsize); istat.is_dbufmore++; goto tryagain; } else { to->exitc = EXITC_MBUF; return dead_link(to, "Buffer allocation error for %s", get_client_name(to, FALSE)); } } /* ** 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->sendM += 1; me.sendM += 1; if (to->acpt != &me) to->acpt->sendM += 1; /* ** This little bit is to stop the sendQ from growing too large when ** there is no need for it to. Thus we call send_queued() every time ** 2k has been added to the queue since the last non-fatal write. ** Also stops us from deliberately building a large sendQ and then ** trying to flood that link with data (possible during the net ** relinking done by servers with a large load). */ if (DBufLength(&to->sendQ)/1024 > to->lastsq) send_queued(to); return 0; }