/* ** zip_buffer ** Zip the content of cptr->zip->outbuf and of the buffer, ** put anything left in cptr->zip->outbuf, update cptr->zip->outcount ** ** if flush is set, then all available data will be compressed, ** otherwise, compression only occurs if there's enough to compress, ** or if we are reaching the maximum allowed size during a connect burst. ** ** will return the uncompressed buffer, length will be updated. ** if a fatal error occurs, length will be set to -1 */ char *zip_buffer(aClient *cptr, char *buffer, int *length, int flush) { z_stream *zout = cptr->zip->out; int r; if (buffer) { /* concatenate buffer in cptr->zip->outbuf */ memcpy((void *)(cptr->zip->outbuf + cptr->zip->outcount), (void *)buffer, *length ); cptr->zip->outcount += *length; } *length = 0; #if 0 if (!flush && ((cptr->zip->outcount < ZIP_MINIMUM) || ((cptr->zip->outcount < (ZIP_MAXIMUM - BUFSIZE)) && CBurst(cptr)))) /* Implement this? more efficient? or not? -- Syzop */ #else if (!flush && (cptr->zip->outcount < ZIP_MINIMUM)) #endif return((char *)NULL); zout->next_in = (Bytef *) cptr->zip->outbuf; zout->avail_in = cptr->zip->outcount; zout->next_out = (Bytef *) zipbuf; zout->avail_out = ZIP_BUFFER_SIZE; switch (r = deflate(zout, Z_PARTIAL_FLUSH)) { case Z_OK: if (zout->avail_in) { /* can this occur?? I hope not... */ sendto_realops("deflate() didn't process all available data!"); } cptr->zip->outcount = 0; *length = ZIP_BUFFER_SIZE - zout->avail_out; return zipbuf; default: /* error ! */ sendto_realops("deflate() error(%d): %s", r, (zout->msg) ? zout->msg : "?"); *length = -1; break; } return((char *)NULL); }
/* ** 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; }