/* * ---------------------------------------------------------------- * Night Light IRC Proxy - Connection SendQ Functions * ---------------------------------------------------------------- * Copyright (C) 1997-2003 Jonas Kvinge * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Last modified by: * Jonas Kvinge (07.07.2003) * */ #define CONN_SENDQ_C #define NEED_SYS_TYPES_H 1 /* Extra types */ #define NEED_SYS_PARAM_H 1 /* Some systems need this */ #define NEED_LIMITS_H 0 /* Kernel limits */ #define NEED_STDARG_H 1 /* va_list, etc */ #define NEED_ERRNO_H 1 /* errno */ #define NEED_CTYPE_H 1 /* isdigit(), etc */ #define NEED_NETINET_IN_H 1 /* in_addr, sockaddr_in, etc */ #define NEED_ARPA_INET_H 0 /* inet_ntoa(), inet_aton(), etc */ #define NEED_STDIO_H 1 /* Standard C UNIX functions */ #define NEED_STDLIB_H 1 /* malloc(), exit(), atoi(), etc */ #define NEED_TIME_H 1 /* time(), etc */ #define NEED_SYSCTL_H 0 /* sysctl(), etc */ #define NEED_SYS_STAT_H 0 /* chmod(), mkdir(), etc */ #define NEED_SYS_UIO_H 0 /* iovec, etc */ #define NEED_FCNTL_H 1 /* open(), creat(), fcntl(), etc */ #define NEED_SYS_IOCTL_H 0 /* ioctl(), etc */ #define NEED_SYS_FILIO_H 0 /* Solaris need this for ioctl(), etc */ #define NEED_UNISTD_H 1 /* Unix standard functions */ #define NEED_STRING_H 1 /* C string functions */ #define NEED_SIGNAL_H 0 /* Signal functions */ #define NEED_SYS_SOCKET_H 0 /* Socket functions */ #define NEED_NETDB_H 0 /* Network database functions */ #define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */ #define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */ #define NEED_ARES 0 /* Functions needed for ares */ #define NEED_SSL 1 /* Needed for SSL support */ #include "includes.h" #include "irc.h" #include "conf.h" #include "access_conf.h" #include "conn.h" #include "conn_connection.h" #include "conn_sendq.h" #include "client.h" #include "client_connection.h" #include "client_notice.h" /* VARIABLES - JONAS (31.07.2001) */ extern struct Conf_Struct ConfS; extern struct Client_Struct *Client_Head; /* CONN_ADDSENDQ FUNCTION - JONAS (01.07.2000) */ void conn_addsendq(struct Conn_Struct *ConnS, const char *const LinePT, ...) { char Line[IRCMSGLEN+1] = ""; va_list Args = { 0 }; struct SendQ_Struct *SendQ = NULL; struct SendQ_Struct *SendQ_NEW = NULL; struct SendQ_Struct *SendQ_PRV = NULL; struct Client_Struct *ClientS = NULL; assert(ConnS != NULL); assert(LinePT != NULL); va_start(Args, LinePT); vsnprintf(Line, IRCMSGLEN+1, LinePT, Args); va_end(Args); if (!Conn_IsSocket(ConnS)) { sysprint(BITMASK_ERROR, "conn_addsendq() called for connection %s without socket: %s.", ConnS->Name, Line); return; } #if DEBUG client_noticealluser(ConnS->User, "Connection %s: Adding line \"%s\" to sendQ.", ConnS->Name, Line); client_noticealluser(ConnS->User, "Connection %s: Allowed buffer to be sent: %ld - Allowed number of lines to be sent: %ld.", ConnS->Name, ConnS->SendQMaxFlushBuffer, ConnS->SendQMaxFlushLines); #endif SendQ_NEW = malloc(sizeof(struct SendQ_Struct)); if (SendQ_NEW == NULL) { return; } memset(SendQ_NEW, 0, sizeof(struct SendQ_Struct)); SendQ_NEW->Line = strdup(Line); if (SendQ_NEW->Line == NULL) { free(SendQ_NEW); return; } SendQ_NEW->Time = NOW; if (strncasecmp(Line, "PASS ", 5) == FALSE) { SendQ_NEW->Priority = 1; } else if (strncasecmp(Line, "NICK ", 5) == FALSE) { SendQ_NEW->Priority = 1; } else if (strncasecmp(Line, "USER ", 5) == FALSE) { SendQ_NEW->Priority = 1; } else if (strncasecmp(Line, "PONG ", 5) == FALSE) { SendQ_NEW->Priority = 1; } else if (strncasecmp(Line, "QUIT ", 5) == FALSE) { SendQ_NEW->Priority = 1; } else if (strncasecmp(Line, "JOIN ", 5) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "PART ", 5) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "ISON ", 5) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "MODE ", 5) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "OPER ", 5) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "KILL ", 5) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "NAMES ", 6) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "LINKS ", 6) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "WHO ", 4) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "WHOIS ", 6) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "AWAY ", 5) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "PING ", 5) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "USERHOST ", 9) == FALSE) { SendQ_NEW->Priority = 2; } else if (strncasecmp(Line, "KICK ", 5) == FALSE) { SendQ_NEW->Priority = 3; } else if (strncasecmp(Line, "PRIVMSG ", 8) == FALSE) { SendQ_NEW->Priority = 4; } else if (strncasecmp(Line, "NOTICE ", 7) == FALSE) { SendQ_NEW->Priority = 4; } else if (strncasecmp(Line, "INVITE ", 7) == FALSE) { SendQ_NEW->Priority = 4; } else if (strncasecmp(Line, "TOPIC ", 6) == FALSE) { SendQ_NEW->Priority = 4; } else { SendQ_NEW->Priority = 4; } if (ConnS->SendQ_Head == NULL) { ConnS->SendQ_Head = SendQ_NEW; } else { for (SendQ = ConnS->SendQ_Head ; SendQ != NULL ;) { if (SendQ->Priority > SendQ_NEW->Priority) { if (SendQ_PRV == NULL) { ConnS->SendQ_Head = SendQ_NEW; SendQ_NEW->Next = SendQ; } else { SendQ_PRV->Next = SendQ_NEW; SendQ_NEW->Next = SendQ; } break; } SendQ_PRV = SendQ; SendQ = SendQ->Next; } if (SendQ == NULL) { SendQ_PRV->Next = SendQ_NEW; } } ++ConnS->NumSendQs; if (ConnS->NumSendQs >= ConfS.ClientMaxSendQ) { #if 0 conn_quit(ConnS, ACCESS_CONF_SENDQFLOOD); #endif for (ClientS = Client_Head ; ClientS != NULL ; ClientS = ClientS->Next) { if (!Client_IsVerified(ClientS)) { continue; } if (ClientS->ConnS != ConnS) { continue; } client_close(ClientS, ACCESS_CONF_SENDQFLOOD); access_conf_adddeny(ClientS->HostName, ACCESS_CONF_SENDQFLOOD); } } } /* CONN_FLUSHSENDQ FUNCTION - JONAS (24.06.2001) */ void conn_flushsendq(struct Conn_Struct *ConnS) { struct SendQ_Struct *SendQ = NULL; struct FlushL_Struct *FlushL = NULL; struct FlushB_Struct *FlushB = NULL; unsigned long int Duration = 0; unsigned short int Count = 0; unsigned short int Len = 0; unsigned short int FlushLen = 0; assert(ConnS != NULL); assert(ConnS->SendQ_Head != NULL); while (ConnS->FlushL_Head != NULL) { FlushL = ConnS->FlushL_Head; Duration = (NOW - FlushL->Time); if (Duration < ConnS->SendLineTime) { break; } ConnS->SendQMaxFlushLines += FlushL->Lines; ConnS->FlushL_Head = FlushL->Next; if (FlushL->Next == NULL) { ConnS->FlushL_Tail = NULL; } else { FlushL->Next->Prev = NULL; } free(FlushL); ConnS->NumFlushLs--; } while (ConnS->FlushB_Head != NULL) { FlushB = ConnS->FlushB_Head; Duration = (NOW - FlushB->Time); if (Duration < ConnS->SendBufferTime) { break; } ConnS->SendQMaxFlushBuffer += FlushB->Len; ConnS->FlushB_Head = FlushB->Next; if (FlushB->Next == NULL) { ConnS->FlushB_Tail = NULL; } else { FlushB->Next->Prev = NULL; } free(FlushB); ConnS->NumFlushBs--; } while ((ConnS->SendQ_Head != NULL) && (ConnS->SendQMaxFlushLines > 0) && (ConnS->SendQMaxFlushBuffer > 0)) { SendQ = ConnS->SendQ_Head; Len = strlen(SendQ->Line) + 2; if (Len > ConnS->SendQMaxFlushBuffer) { break; } ConnS->NumSendQs--; ConnS->SendQ_Head = ConnS->SendQ_Head->Next; conn_addsend(ConnS, SendQ->Line); ConnS->SendQMaxFlushLines--; ConnS->SendQMaxFlushBuffer -= Len; FlushLen += Len; free(SendQ->Line); free(SendQ); Count++; } if (Count > 0) { conn_addflushl(ConnS, Count); conn_addflushb(ConnS, FlushLen); } } /* CONN_INITSENDQ FUNCTION - JONAS (01.07.2000) */ void conn_initsendq(struct Conn_Struct *ConnS) { struct SendQ_Struct *SendQ = NULL; assert(ConnS != NULL); conn_initflushl(ConnS); conn_initflushb(ConnS); while (ConnS->SendQ_Head != NULL) { SendQ = ConnS->SendQ_Head; ConnS->SendQ_Head = ConnS->SendQ_Head->Next; free(SendQ->Line); free(SendQ); ConnS->NumSendQs--; } assert(ConnS->NumSendQs == 0); ConnS->SendQMaxFlushLines = ConnS->SendMaxLines; ConnS->SendQMaxFlushBuffer = ConnS->SendMaxBuffer; } /* CONN_ADDFLUSHL FUNCTION - JONAS (24.06.2001) */ void conn_addflushl(struct Conn_Struct *ConnS, const unsigned short int Lines) { struct FlushL_Struct *FlushL = NULL; struct FlushL_Struct *FlushL_NEW = NULL; assert(ConnS != NULL); FlushL_NEW = malloc(sizeof(struct FlushL_Struct)); if (FlushL_NEW == NULL) { return; } memset(FlushL_NEW, 0, sizeof(struct FlushL_Struct)); FlushL_NEW->Lines = Lines; FlushL_NEW->Time = NOW; if (ConnS->FlushL_Head == NULL) { ConnS->FlushL_Head = FlushL_NEW; ConnS->FlushL_Tail = FlushL_NEW; } else { FlushL = ConnS->FlushL_Tail; FlushL->Next = FlushL_NEW; FlushL_NEW->Prev = FlushL; ConnS->FlushL_Tail = FlushL_NEW; } ConnS->NumFlushLs++; } /* CONN_INITFLUSHL FUNCTION - JONAS (24.06.2001) */ void conn_initflushl(struct Conn_Struct *ConnS) { struct FlushL_Struct *FlushL = NULL; assert(ConnS != NULL); while (ConnS->FlushL_Head != NULL) { FlushL = ConnS->FlushL_Head; ConnS->FlushL_Head = ConnS->FlushL_Head->Next; free(FlushL); ConnS->NumFlushLs--; } ConnS->FlushL_Tail = NULL; assert(ConnS->NumFlushLs == 0); ConnS->SendQMaxFlushLines = ConnS->SendMaxLines; } /* CONN_ADDFLUSHB FUNCTION - JONAS (24.06.2001) */ void conn_addflushb(struct Conn_Struct *ConnS, const unsigned short int Len) { struct FlushB_Struct *FlushB = NULL; struct FlushB_Struct *FlushB_NEW = NULL; assert(ConnS != NULL); FlushB_NEW = malloc(sizeof(struct FlushB_Struct)); if (FlushB_NEW == NULL) { return; } memset(FlushB_NEW, 0, sizeof(struct FlushB_Struct)); FlushB_NEW->Len = Len; FlushB_NEW->Time = NOW; if (ConnS->FlushB_Head == NULL) { ConnS->FlushB_Head = FlushB_NEW; ConnS->FlushB_Tail = FlushB_NEW; } else { FlushB = ConnS->FlushB_Tail; FlushB->Next = FlushB_NEW; FlushB_NEW->Prev = FlushB; ConnS->FlushB_Tail = FlushB_NEW; } ConnS->NumFlushBs++; } /* CONN_INITFLUSHB FUNCTION - JONAS (24.06.2001) */ void conn_initflushb(struct Conn_Struct *ConnS) { struct FlushB_Struct *FlushB = NULL; assert(ConnS != NULL); while (ConnS->FlushB_Head != NULL) { FlushB = ConnS->FlushB_Head; ConnS->FlushB_Head = ConnS->FlushB_Head->Next; free(FlushB); ConnS->NumFlushBs--; } ConnS->FlushB_Tail = NULL; assert(ConnS->NumFlushBs == 0); ConnS->SendQMaxFlushBuffer = ConnS->SendMaxBuffer; }