X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/c48eb01dbed808464cc3f702cc910f3962351825..7bab07d4d30245bf5ba272b236dc7b1c1e309c4d:/src/packet.c diff --git a/src/packet.c b/src/packet.c index 054f416..1434f2c 100644 --- a/src/packet.c +++ b/src/packet.c @@ -165,63 +165,189 @@ flood_endgrace(struct Client *client_p) client_p->localClient->sent_parsed = 0; } -/* - * flood_recalc - * - * recalculate the number of allowed flood lines. this should be called - * once a second on any given client. We then attempt to flush some data. - */ -void -flood_recalc(void *unused) -{ - rb_dlink_node *ptr, *next; - struct Client *client_p; - - RB_DLINK_FOREACH_SAFE(ptr, next, lclient_list.head) - { - client_p = ptr->data; - - if(unlikely(IsMe(client_p))) - continue; - - if(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(unlikely(IsAnyDead(client_p))) - continue; - - } - - RB_DLINK_FOREACH_SAFE(ptr, next, unknown_list.head) - { - client_p = ptr->data; - - if(client_p->localClient == NULL) - continue; - - client_p->localClient->sent_parsed--; - - 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); - } +/* + * flood_recalc + * + * recalculate the number of allowed flood lines. this should be called + * once a second on any given client. We then attempt to flush some data. + */ +void +flood_recalc(void *unused) +{ + rb_dlink_node *ptr, *next; + struct Client *client_p; + + RB_DLINK_FOREACH_SAFE(ptr, next, lclient_list.head) + { + client_p = ptr->data; + + if(unlikely(IsMe(client_p))) + continue; + + if(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(unlikely(IsAnyDead(client_p))) + continue; + + } + + RB_DLINK_FOREACH_SAFE(ptr, next, unknown_list.head) + { + client_p = ptr->data; + + if(client_p->localClient == NULL) + continue; + + client_p->localClient->sent_parsed--; + + 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); + } +} + +/* + * read_ctrl_packet - Read a 'packet' of data from a servlink control + * link and process it. + */ +void +read_ctrl_packet(rb_fde_t *F, void *data) +{ + 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; + + reply = &lserver->slinkrpl; + + + if(!reply->command) + { + reply->gotdatalen = 0; + reply->readdata = 0; + reply->data = NULL; + + length = rb_read(F, tmp, 1); + + if(length <= 0) + { + if((length == -1) && rb_ignore_errno(errno)) + goto nodata; + error_exit_client(server, length); + return; + } + + reply->command = tmp[0]; + } + + for (replydef = slinkrpltab; replydef->handler; replydef++) + { + if((int)replydef->replyid == reply->command) + break; + } + + /* 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((replydef->flags & SLINKRPL_FLAG_DATA) && (reply->gotdatalen < 2)) + { + /* we need a datalen u16 which we don't have yet... */ + length = rb_read(F, len, (2 - reply->gotdatalen)); + if(length <= 0) + { + if((length == -1) && rb_ignore_errno(errno)) + goto nodata; + error_exit_client(server, length); + return; + } + + 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 = rb_malloc(reply->datalen); + } + + if(reply->gotdatalen < 2) + return; /* wait for more data */ + } + + if(reply->readdata < reply->datalen) /* try to get any remaining data */ + { + length = rb_read(F, (reply->data + reply->readdata), + (reply->datalen - reply->readdata)); + if(length <= 0) + { + if((length == -1) && rb_ignore_errno(errno)) + goto nodata; + error_exit_client(server, length); + return; + } + + reply->readdata += length; + if(reply->readdata < reply->datalen) + return; /* wait for more data */ + } + +#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) + rb_free(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(F, RB_SELECT_READ, read_ctrl_packet, server); } /* @@ -252,17 +378,16 @@ read_packet(rb_fde_t * F, void *data) */ length = rb_read(client_p->localClient->F, readBuf, READBUF_SIZE); - if(length <= 0) + if(length < 0) { if(rb_ignore_errno(errno)) - { rb_setselect(client_p->localClient->F, RB_SELECT_READ, read_packet, client_p); - } else + else error_exit_client(client_p, length); return; } - if(length == 0) + else if(length == 0) { error_exit_client(client_p, length); return;