Beispiel #1
0
/** 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);
}
Beispiel #2
0
/* 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;
}
Beispiel #3
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);
}
Beispiel #4
0
/** 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");
}
Beispiel #5
0
Datei: send.c Projekt: ahf/irc
/*
** 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;
}
Beispiel #6
0
Datei: send.c Projekt: ahf/irc
/*
** 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;
}