1 /*
2 * ----------------------------------------------------------------
3 * ircproxy - Connection SendQ Functions
4 * ----------------------------------------------------------------
5 * Copyright (C) 1997-2009 Jonas Kvinge
6 *
7 * This file is part of ircproxy.
8 *
9 * ircproxy is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * ircproxy is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ircproxy. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * Additional permission under GNU GPL version 3 section 7
23 *
24 * If you modify ircproxy, or any covered work, by linking or
25 * combining it with openssl (or a modified version of that library),
26 * containing parts covered by the terms of the OpenSSL License and the
27 * SSLeay License, the licensors of ircproxy grant you additional
28 * permission to convey the resulting work.
29 *
30 * $Id: conn_sendq.c 54 2009-03-18 18:23:29Z jonasio $
31 *
32 */
33
34 #define CONN_SENDQ_C
35
36 #define NEED_SYS_TYPES_H 1 /* Extra types */
37 #define NEED_SYS_PARAM_H 1 /* Some systems need this */
38 #define NEED_LIMITS_H 0 /* Kernel limits */
39 #define NEED_STDARG_H 1 /* va_list, etc */
40 #define NEED_ERRNO_H 1 /* errno */
41 #define NEED_CTYPE_H 1 /* isdigit(), etc */
42 #define NEED_NETINET_IN_H 1 /* in_addr, sockaddr_in, etc */
43 #define NEED_ARPA_INET_H 0 /* inet_ntoa(), inet_aton(), etc */
44 #define NEED_STDIO_H 1 /* Standard C UNIX functions */
45 #define NEED_STDLIB_H 1 /* malloc(), exit(), atoi(), etc */
46 #define NEED_TIME_H 1 /* time(), etc */
47 #define NEED_SYSCTL_H 0 /* sysctl(), etc */
48 #define NEED_SYS_STAT_H 0 /* chmod(), mkdir(), etc */
49 #define NEED_SYS_UIO_H 0 /* iovec, etc */
50 #define NEED_FCNTL_H 1 /* open(), creat(), fcntl(), etc */
51 #define NEED_SYS_IOCTL_H 0 /* ioctl(), etc */
52 #define NEED_SYS_FILIO_H 0 /* Solaris need this for ioctl(), etc */
53 #define NEED_UNISTD_H 1 /* Unix standard functions */
54 #define NEED_STRING_H 1 /* C string functions */
55 #define NEED_SIGNAL_H 0 /* Signal functions */
56 #define NEED_SYS_SOCKET_H 0 /* Socket functions */
57 #define NEED_NETDB_H 0 /* Network database functions */
58 #define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */
59 #define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */
60 #define NEED_ARES 0 /* Functions needed for ares */
61 #define NEED_SSL 1 /* Needed for SSL support */
62
63 #include "includes.h"
64 #include "irc.h"
65
66 #include "conf.h"
67
68 #include "access_conf.h"
69
70 #include "conn.h"
71 #include "conn_conf.h"
72 #include "conn_connection.h"
73 #include "conn_sendq.h"
74 #include "conn_log.h"
75
76 #include "client.h"
77 #include "client_connection.h"
78 #include "client_notice.h"
79
80 /* VARIABLES - JONAS (31.07.2001) */
81
82 extern struct Conf_Struct ConfS;
83 extern struct Client_Struct *Client_Head;
84
85 /* CONN_ADDSENDQ FUNCTION - JONAS (01.07.2000) */
86
conn_addsendq(struct Conn_Struct * ConnS,const char * const LinePT,...)87 void conn_addsendq(struct Conn_Struct *ConnS, const char *const LinePT, ...) {
88
89 char Line[IRC_MSGLEN+1] = "";
90 va_list Args;
91 struct SendQ_Struct *SendQ = NULL;
92 struct SendQ_Struct *SendQ_NEW = NULL;
93 struct SendQ_Struct *SendQ_PRV = NULL;
94 struct Client_Struct *ClientS = NULL;
95
96 assert(ConnS != NULL);
97 assert(LinePT != NULL);
98
99 va_start(Args, LinePT);
100 vsnprintf(Line, IRC_MSGLEN+1, LinePT, Args);
101 va_end(Args);
102
103 if (!Conn_IsSocket(ConnS)) {
104 sysprint(BITMASK_ERROR, "conn_addsendq() called for connection %s without socket: %s.", ConnS->Name, Line);
105 return;
106 }
107
108 if (ConnConf_IsRawLog(ConnS)) {
109 if (strncasecmp(Line, "PASS ", 5) == FALSE) { conn_rawlog(ConnS, "---> PASS <HIDDEN>"); }
110 else if (strncasecmp(Line, "OPER ", 5) == FALSE) { conn_rawlog(ConnS, "---> OPER <HIDDEN>"); }
111 else { conn_rawlog(ConnS, "---> %s", Line); }
112 }
113
114 #if DEBUG && (BITMASK_DEBUG_OPTIONS & BITMASK_DEBUG_CONN_SENDQ)
115 client_noticealluser(ConnS->User, "Connection %s: Adding line \"%s\" to sendQ.", ConnS->Name, Line);
116 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);
117 #endif
118
119 SendQ_NEW = malloc(sizeof(struct SendQ_Struct));
120 if (SendQ_NEW == NULL) { return; }
121
122 memset(SendQ_NEW, 0, sizeof(struct SendQ_Struct));
123
124 SendQ_NEW->Line = strdup(Line);
125 if (SendQ_NEW->Line == NULL) {
126 free(SendQ_NEW);
127 return;
128 }
129
130 SendQ_NEW->Time = NOW;
131
132 if (strncasecmp(Line, "PASS ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
133 else if (strncasecmp(Line, "NICK ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
134 else if (strncasecmp(Line, "USER ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
135 else if (strncasecmp(Line, "PONG ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
136 else if (strncasecmp(Line, "QUIT ", 5) == FALSE) { SendQ_NEW->Priority = 1; }
137
138 else if (strncasecmp(Line, "JOIN ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
139 else if (strncasecmp(Line, "PART ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
140 else if (strncasecmp(Line, "ISON ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
141 else if (strncasecmp(Line, "MODE ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
142 else if (strncasecmp(Line, "OPER ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
143 else if (strncasecmp(Line, "KILL ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
144 else if (strncasecmp(Line, "NAMES ", 6) == FALSE) { SendQ_NEW->Priority = 2; }
145 else if (strncasecmp(Line, "LINKS ", 6) == FALSE) { SendQ_NEW->Priority = 2; }
146 else if (strncasecmp(Line, "WHO ", 4) == FALSE) { SendQ_NEW->Priority = 2; }
147 else if (strncasecmp(Line, "WHOIS ", 6) == FALSE) { SendQ_NEW->Priority = 2; }
148 else if (strncasecmp(Line, "AWAY ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
149 else if (strncasecmp(Line, "PING ", 5) == FALSE) { SendQ_NEW->Priority = 2; }
150 else if (strncasecmp(Line, "USERHOST ", 9) == FALSE) { SendQ_NEW->Priority = 2; }
151
152 else if (strncasecmp(Line, "KICK ", 5) == FALSE) { SendQ_NEW->Priority = 3; }
153
154 else if (strncasecmp(Line, "PRIVMSG ", 8) == FALSE) { SendQ_NEW->Priority = 4; }
155 else if (strncasecmp(Line, "NOTICE ", 7) == FALSE) { SendQ_NEW->Priority = 4; }
156 else if (strncasecmp(Line, "INVITE ", 7) == FALSE) { SendQ_NEW->Priority = 4; }
157 else if (strncasecmp(Line, "TOPIC ", 6) == FALSE) { SendQ_NEW->Priority = 4; }
158
159 else { SendQ_NEW->Priority = 4; }
160
161 if (ConnS->SendQ_Head == NULL) { ConnS->SendQ_Head = SendQ_NEW; }
162 else {
163 for (SendQ = ConnS->SendQ_Head ; SendQ != NULL ;) {
164 if (SendQ->Priority > SendQ_NEW->Priority) {
165 if (SendQ_PRV == NULL) {
166 ConnS->SendQ_Head = SendQ_NEW;
167 SendQ_NEW->Next = SendQ;
168 }
169 else {
170 SendQ_PRV->Next = SendQ_NEW;
171 SendQ_NEW->Next = SendQ;
172 }
173 break;
174 }
175 SendQ_PRV = SendQ;
176 SendQ = SendQ->Next;
177 }
178 if (SendQ == NULL) { SendQ_PRV->Next = SendQ_NEW; }
179 }
180
181 ++ConnS->NumSendQs;
182
183 if (ConnS->NumSendQs >= ConfS.ClientMaxSendQ) {
184 #if 0
185 conn_quit(ConnS, ACCESS_CONF_SENDQFLOOD);
186 #endif
187 for (ClientS = Client_Head ; ClientS != NULL ; ClientS = ClientS->Next) {
188 if (!Client_IsVerified(ClientS)) { continue; }
189 if (ClientS->ConnS != ConnS) { continue; }
190 client_close(ClientS, ACCESS_CONF_SENDQFLOOD);
191 access_conf_adddeny(ClientS->HostName, ACCESS_CONF_SENDQFLOOD);
192 }
193 }
194
195 }
196
197 /* CONN_FLUSHSENDQ FUNCTION - JONAS (24.06.2001) */
198
conn_flushsendq(struct Conn_Struct * ConnS)199 void conn_flushsendq(struct Conn_Struct *ConnS) {
200
201 struct SendQ_Struct *SendQ = NULL;
202 struct FlushL_Struct *FlushL = NULL;
203 struct FlushB_Struct *FlushB = NULL;
204 unsigned long int Duration = 0;
205 unsigned short int Count = 0;
206 unsigned short int Len = 0;
207 unsigned short int FlushLen = 0;
208
209 assert(ConnS != NULL);
210 assert(ConnS->SendQ_Head != NULL);
211
212 while (ConnS->FlushL_Head != NULL) {
213 FlushL = ConnS->FlushL_Head;
214 Duration = (NOW - FlushL->Time);
215 if (Duration < ConnS->SendLineTime) { break; }
216 ConnS->SendQMaxFlushLines += FlushL->Lines;
217
218 ConnS->FlushL_Head = FlushL->Next;
219 if (FlushL->Next == NULL) { ConnS->FlushL_Tail = NULL; }
220 else { FlushL->Next->Prev = NULL; }
221
222 free(FlushL);
223 ConnS->NumFlushLs--;
224 }
225
226 while (ConnS->FlushB_Head != NULL) {
227 FlushB = ConnS->FlushB_Head;
228 Duration = (NOW - FlushB->Time);
229 if (Duration < ConnS->SendBufferTime) { break; }
230 ConnS->SendQMaxFlushBuffer += FlushB->Len;
231
232 ConnS->FlushB_Head = FlushB->Next;
233 if (FlushB->Next == NULL) { ConnS->FlushB_Tail = NULL; }
234 else { FlushB->Next->Prev = NULL; }
235
236 free(FlushB);
237 ConnS->NumFlushBs--;
238 }
239
240 while ((ConnS->SendQ_Head != NULL) && (ConnS->SendQMaxFlushLines > 0) && (ConnS->SendQMaxFlushBuffer > 0)) {
241 SendQ = ConnS->SendQ_Head;
242 Len = strlen(SendQ->Line) + 2;
243 if (Len > ConnS->SendQMaxFlushBuffer) { break; }
244 ConnS->NumSendQs--;
245 ConnS->SendQ_Head = ConnS->SendQ_Head->Next;
246 conn_addsend(ConnS, SendQ->Line);
247 ConnS->SendQMaxFlushLines--;
248 ConnS->SendQMaxFlushBuffer -= Len;
249 FlushLen += Len;
250 free(SendQ->Line);
251 free(SendQ);
252 Count++;
253 }
254
255 if (Count > 0) {
256 conn_addflushl(ConnS, Count);
257 conn_addflushb(ConnS, FlushLen);
258 }
259
260 }
261
262 /* CONN_INITSENDQ FUNCTION - JONAS (01.07.2000) */
263
conn_initsendq(struct Conn_Struct * ConnS)264 void conn_initsendq(struct Conn_Struct *ConnS) {
265
266 struct SendQ_Struct *SendQ = NULL;
267
268 assert(ConnS != NULL);
269
270 conn_initflushl(ConnS);
271 conn_initflushb(ConnS);
272
273 while (ConnS->SendQ_Head != NULL) {
274 SendQ = ConnS->SendQ_Head;
275 ConnS->SendQ_Head = ConnS->SendQ_Head->Next;
276 free(SendQ->Line);
277 free(SendQ);
278 ConnS->NumSendQs--;
279 }
280 assert(ConnS->NumSendQs == 0);
281
282 ConnS->SendQMaxFlushLines = ConnS->SendMaxLines;
283 ConnS->SendQMaxFlushBuffer = ConnS->SendMaxBuffer;
284
285 }
286
287 /* CONN_ADDFLUSHL FUNCTION - JONAS (24.06.2001) */
288
conn_addflushl(struct Conn_Struct * ConnS,const unsigned short int Lines)289 void conn_addflushl(struct Conn_Struct *ConnS, const unsigned short int Lines) {
290
291 struct FlushL_Struct *FlushL = NULL;
292 struct FlushL_Struct *FlushL_NEW = NULL;
293
294 assert(ConnS != NULL);
295
296 FlushL_NEW = malloc(sizeof(struct FlushL_Struct));
297 if (FlushL_NEW == NULL) { return; }
298
299 memset(FlushL_NEW, 0, sizeof(struct FlushL_Struct));
300
301 FlushL_NEW->Lines = Lines;
302 FlushL_NEW->Time = NOW;
303
304 if (ConnS->FlushL_Head == NULL) {
305 ConnS->FlushL_Head = FlushL_NEW;
306 ConnS->FlushL_Tail = FlushL_NEW;
307 }
308 else {
309 FlushL = ConnS->FlushL_Tail;
310 FlushL->Next = FlushL_NEW;
311 FlushL_NEW->Prev = FlushL;
312 ConnS->FlushL_Tail = FlushL_NEW;
313 }
314
315 ConnS->NumFlushLs++;
316
317 }
318
319 /* CONN_INITFLUSHL FUNCTION - JONAS (24.06.2001) */
320
conn_initflushl(struct Conn_Struct * ConnS)321 void conn_initflushl(struct Conn_Struct *ConnS) {
322
323 struct FlushL_Struct *FlushL = NULL;
324
325 assert(ConnS != NULL);
326
327 while (ConnS->FlushL_Head != NULL) {
328 FlushL = ConnS->FlushL_Head;
329 ConnS->FlushL_Head = ConnS->FlushL_Head->Next;
330 free(FlushL);
331 ConnS->NumFlushLs--;
332 }
333 ConnS->FlushL_Tail = NULL;
334 assert(ConnS->NumFlushLs == 0);
335
336 ConnS->SendQMaxFlushLines = ConnS->SendMaxLines;
337
338 }
339
340 /* CONN_ADDFLUSHB FUNCTION - JONAS (24.06.2001) */
341
conn_addflushb(struct Conn_Struct * ConnS,const unsigned short int Len)342 void conn_addflushb(struct Conn_Struct *ConnS, const unsigned short int Len) {
343
344 struct FlushB_Struct *FlushB = NULL;
345 struct FlushB_Struct *FlushB_NEW = NULL;
346
347 assert(ConnS != NULL);
348
349 FlushB_NEW = malloc(sizeof(struct FlushB_Struct));
350 if (FlushB_NEW == NULL) { return; }
351
352 memset(FlushB_NEW, 0, sizeof(struct FlushB_Struct));
353
354 FlushB_NEW->Len = Len;
355 FlushB_NEW->Time = NOW;
356
357 if (ConnS->FlushB_Head == NULL) {
358 ConnS->FlushB_Head = FlushB_NEW;
359 ConnS->FlushB_Tail = FlushB_NEW;
360 }
361 else {
362 FlushB = ConnS->FlushB_Tail;
363 FlushB->Next = FlushB_NEW;
364 FlushB_NEW->Prev = FlushB;
365 ConnS->FlushB_Tail = FlushB_NEW;
366 }
367
368 ConnS->NumFlushBs++;
369
370 }
371
372 /* CONN_INITFLUSHB FUNCTION - JONAS (24.06.2001) */
373
conn_initflushb(struct Conn_Struct * ConnS)374 void conn_initflushb(struct Conn_Struct *ConnS) {
375
376 struct FlushB_Struct *FlushB = NULL;
377
378 assert(ConnS != NULL);
379
380 while (ConnS->FlushB_Head != NULL) {
381 FlushB = ConnS->FlushB_Head;
382 ConnS->FlushB_Head = ConnS->FlushB_Head->Next;
383 free(FlushB);
384 ConnS->NumFlushBs--;
385 }
386 ConnS->FlushB_Tail = NULL;
387 assert(ConnS->NumFlushBs == 0);
388
389 ConnS->SendQMaxFlushBuffer = ConnS->SendMaxBuffer;
390
391 }
392