X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/38e6acddad741b38a475fe3d10dfffb3c6d6c639..dc34aae05e6e299a6c53c60b728d73ecb88b21bf:/src/packet.c diff --git a/src/packet.c b/src/packet.c index 98bace1..707ddbb 100644 --- a/src/packet.c +++ b/src/packet.c @@ -21,11 +21,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * - * $Id: packet.c 3446 2007-05-14 22:21:16Z jilles $ */ #include "stdinc.h" -#include "tools.h" -#include "commio.h" #include "s_conf.h" #include "s_serv.h" #include "client.h" @@ -33,8 +30,7 @@ #include "ircd.h" #include "parse.h" #include "packet.h" -#include "irc_string.h" -#include "memory.h" +#include "match.h" #include "hook.h" #include "send.h" @@ -61,7 +57,7 @@ parse_client_queued(struct Client *client_p) if(client_p->localClient->sent_parsed >= client_p->localClient->allow_read) break; - dolen = linebuf_get(&client_p->localClient-> + dolen = rb_linebuf_get(&client_p->localClient-> buf_recvq, readBuf, READBUF_SIZE, LINEBUF_COMPLETE, LINEBUF_PARSED); @@ -91,7 +87,7 @@ parse_client_queued(struct Client *client_p) if(IsAnyServer(client_p) || IsExemptFlood(client_p)) { - while (!IsAnyDead(client_p) && (dolen = linebuf_get(&client_p->localClient->buf_recvq, + while (!IsAnyDead(client_p) && (dolen = rb_linebuf_get(&client_p->localClient->buf_recvq, readBuf, READBUF_SIZE, LINEBUF_COMPLETE, LINEBUF_PARSED)) > 0) { @@ -102,7 +98,12 @@ parse_client_queued(struct Client *client_p) { if(IsOper(client_p) && ConfigFileEntry.no_oper_flood) - checkflood = 0; + { + if (ConfigFileEntry.true_no_oper_flood) + checkflood = -1; + else + checkflood = 0; + } /* * Handle flood protection here - if we exceed our flood limit on * messages in this loop, we simply drop out of the loop prematurely. @@ -132,10 +133,10 @@ parse_client_queued(struct Client *client_p) /* allow opers 4 times the amount of messages as users. why 4? * why not. :) --fl_ */ - else if(client_p->localClient->sent_parsed >= (4 * client_p->localClient->allow_read)) + else if(client_p->localClient->sent_parsed >= (4 * client_p->localClient->allow_read) && checkflood != -1) break; - dolen = linebuf_get(&client_p->localClient-> + dolen = rb_linebuf_get(&client_p->localClient-> buf_recvq, readBuf, READBUF_SIZE, LINEBUF_COMPLETE, LINEBUF_PARSED); @@ -175,169 +176,63 @@ flood_endgrace(struct Client *client_p) * once a second on any given client. We then attempt to flush some data. */ void -flood_recalc(int fd, void *data) -{ - struct Client *client_p = data; - struct LocalUser *lclient_p = client_p->localClient; - - /* This can happen in the event that the client detached. */ - if(!lclient_p) - return; - - /* allow a bursting client their allocation per second, allow - * a client whos flooding an extra 2 per second - */ - if(IsFloodDone(client_p)) - lclient_p->sent_parsed -= 2; - else - lclient_p->sent_parsed = 0; - - if(lclient_p->sent_parsed < 0) - lclient_p->sent_parsed = 0; - - if(--lclient_p->actually_read < 0) - lclient_p->actually_read = 0; - - parse_client_queued(client_p); - - if(IsAnyDead(client_p)) - return; - - /* and finally, reset the flood check */ - rb_setflush(fd, 1000, flood_recalc, client_p); -} - -/* - * read_ctrl_packet - Read a 'packet' of data from a servlink control - * link and process it. - */ -void -read_ctrl_packet(int fd, void *data) +flood_recalc(void *unused) { - struct Client *server = data; - struct LocalUser *lserver = server->localClient; - struct SlinkRpl *reply; - int length = 0; - unsigned char tmp[2]; - unsigned char *len = tmp; - struct SlinkRplDef *replydef; -#ifdef USE_IODEBUG_HOOKS - hook_data_int hdata; -#endif - - s_assert(lserver != NULL); - if(IsAnyDead(server)) - return; + rb_dlink_node *ptr, *next; + struct Client *client_p; - reply = &lserver->slinkrpl; - - - if(!reply->command) + RB_DLINK_FOREACH_SAFE(ptr, next, lclient_list.head) { - reply->gotdatalen = 0; - reply->readdata = 0; - reply->data = NULL; - - length = read(fd, tmp, 1); + client_p = ptr->data; - if(length <= 0) - { - if((length == -1) && ignoreErrno(errno)) - goto nodata; - error_exit_client(server, length); - return; - } + if(rb_unlikely(IsMe(client_p))) + continue; + + if(rb_unlikely(client_p->localClient == NULL)) + continue; + + if(IsFloodDone(client_p)) + client_p->localClient->sent_parsed -= 2; + else + client_p->localClient->sent_parsed = 0; + + if(client_p->localClient->sent_parsed < 0) + client_p->localClient->sent_parsed = 0; + + if(--client_p->localClient->actually_read < 0) + client_p->localClient->actually_read = 0; + + parse_client_queued(client_p); + + if(rb_unlikely(IsAnyDead(client_p))) + continue; - reply->command = tmp[0]; } - for (replydef = slinkrpltab; replydef->handler; replydef++) + RB_DLINK_FOREACH_SAFE(ptr, next, unknown_list.head) { - if((int)replydef->replyid == reply->command) - break; - } + client_p = ptr->data; - /* we should be able to trust a local slink process... - * and if it sends an invalid command, that's a bug.. */ - s_assert(replydef->handler); + if(client_p->localClient == NULL) + continue; - if((replydef->flags & SLINKRPL_FLAG_DATA) && (reply->gotdatalen < 2)) - { - /* we need a datalen u16 which we don't have yet... */ - length = read(fd, len, (2 - reply->gotdatalen)); - if(length <= 0) - { - if((length == -1) && ignoreErrno(errno)) - goto nodata; - error_exit_client(server, length); - return; - } + client_p->localClient->sent_parsed--; - if(reply->gotdatalen == 0) - { - reply->datalen = *len << 8; - reply->gotdatalen++; - length--; - len++; - } - if(length && (reply->gotdatalen == 1)) - { - reply->datalen |= *len; - reply->gotdatalen++; - if(reply->datalen > 0) - reply->data = MyMalloc(reply->datalen); - } + if(client_p->localClient->sent_parsed < 0) + client_p->localClient->sent_parsed = 0; - if(reply->gotdatalen < 2) - return; /* wait for more data */ - } + if(--client_p->localClient->actually_read < 0) + client_p->localClient->actually_read = 0; - if(reply->readdata < reply->datalen) /* try to get any remaining data */ - { - length = read(fd, (reply->data + reply->readdata), - (reply->datalen - reply->readdata)); - if(length <= 0) - { - if((length == -1) && ignoreErrno(errno)) - goto nodata; - error_exit_client(server, length); - return; - } - - reply->readdata += length; - if(reply->readdata < reply->datalen) - return; /* wait for more data */ + parse_client_queued(client_p); } - -#ifdef USE_IODEBUG_HOOKS - hdata.client = server; - hdata.arg1 = NULL; - hdata.arg2 = reply->command; - hdata.data = NULL; - call_hook(h_iorecvctrl_id, &hdata); -#endif - - /* we now have the command and any data, pass it off to the handler */ - (*replydef->handler) (reply->command, reply->datalen, reply->data, server); - - /* reset SlinkRpl */ - if(reply->datalen > 0) - MyFree(reply->data); - reply->command = 0; - - if(IsAnyDead(server)) - return; - - nodata: - /* If we get here, we need to register for another COMM_SELECT_READ */ - rb_setselect(fd, FDLIST_SERVER, COMM_SELECT_READ, read_ctrl_packet, server, 0); } /* * read_packet - Read a 'packet' of data from a connection and process it. */ void -read_packet(int fd, void *data) +read_packet(rb_fde_t * F, void *data) { struct Client *client_p = data; struct LocalUser *lclient_p = client_p->localClient; @@ -348,81 +243,83 @@ read_packet(int fd, void *data) #ifdef USE_IODEBUG_HOOKS hook_data_int hdata; #endif - if(IsAnyDead(client_p)) - return; - /* - * Read some data. We *used to* do anti-flood protection here, but - * I personally think it makes the code too hairy to make sane. - * -- adrian - */ - length = client_p->localClient->F->read_impl(client_p->localClient->F, readBuf, READBUF_SIZE); - - if(length <= 0) + while(1) { - if((length == -1) && ignoreErrno(errno)) + if(IsAnyDead(client_p)) + return; + + /* + * Read some data. We *used to* do anti-flood protection here, but + * I personally think it makes the code too hairy to make sane. + * -- adrian + */ + length = rb_read(client_p->localClient->F, readBuf, READBUF_SIZE); + + if(length < 0) { - rb_setselect(client_p->localClient->F->fd, FDLIST_IDLECLIENT, - COMM_SELECT_READ, read_packet, client_p, 0); + if(rb_ignore_errno(errno)) + rb_setselect(client_p->localClient->F, + RB_SELECT_READ, read_packet, client_p); + else + error_exit_client(client_p, length); + return; + } + else if(length == 0) + { + error_exit_client(client_p, length); return; } - error_exit_client(client_p, length); - return; - } #ifdef USE_IODEBUG_HOOKS - hdata.client = client_p; - hdata.arg1 = readBuf; - hdata.arg2 = length; - call_hook(h_iorecv_id, &hdata); + hdata.client = client_p; + hdata.arg1 = readBuf; + hdata.arg2 = length; + call_hook(h_iorecv_id, &hdata); #endif - if(client_p->localClient->lasttime < CurrentTime) - client_p->localClient->lasttime = CurrentTime; - client_p->flags &= ~FLAGS_PINGSENT; + if(client_p->localClient->lasttime < rb_current_time()) + client_p->localClient->lasttime = rb_current_time(); + client_p->flags &= ~FLAGS_PINGSENT; - /* - * Before we even think of parsing what we just read, stick - * it on the end of the receive queue and do it when its - * turn comes around. - */ - if(IsHandshake(client_p) || IsUnknown(client_p)) - binary = 1; + /* + * Before we even think of parsing what we just read, stick + * it on the end of the receive queue and do it when its + * turn comes around. + */ + if(IsHandshake(client_p) || IsUnknown(client_p)) + binary = 1; - lbuf_len = linebuf_parse(&client_p->localClient->buf_recvq, readBuf, length, binary); + lbuf_len = rb_linebuf_parse(&client_p->localClient->buf_recvq, readBuf, length, binary); - lclient_p->actually_read += lbuf_len; + lclient_p->actually_read += lbuf_len; - if(IsAnyDead(client_p)) - return; - - /* Attempt to parse what we have */ - parse_client_queued(client_p); + if(IsAnyDead(client_p)) + return; + + /* Attempt to parse what we have */ + parse_client_queued(client_p); - if(IsAnyDead(client_p)) - return; - - /* Check to make sure we're not flooding */ - if(!IsAnyServer(client_p) && - (linebuf_alloclen(&client_p->localClient->buf_recvq) > ConfigFileEntry.client_flood)) - { - if(!(ConfigFileEntry.no_oper_flood && IsOper(client_p))) - { - exit_client(client_p, client_p, client_p, "Excess Flood"); + if(IsAnyDead(client_p)) return; + + /* Check to make sure we're not flooding */ + if(!IsAnyServer(client_p) && + (rb_linebuf_alloclen(&client_p->localClient->buf_recvq) > ConfigFileEntry.client_flood)) + { + if(!(ConfigFileEntry.no_oper_flood && IsOper(client_p))) + { + exit_client(client_p, client_p, client_p, "Excess Flood"); + return; + } } - } - /* If we get here, we need to register for another COMM_SELECT_READ */ - if(PARSE_AS_SERVER(client_p)) - { - rb_setselect(client_p->localClient->F->fd, FDLIST_SERVER, COMM_SELECT_READ, - read_packet, client_p, 0); - } - else - { - rb_setselect(client_p->localClient->F->fd, FDLIST_IDLECLIENT, - COMM_SELECT_READ, read_packet, client_p, 0); + /* bail if short read */ + if(length < READBUF_SIZE) + { + rb_setselect(client_p->localClient->F, RB_SELECT_READ, read_packet, client_p); + return; + } } }