1 /* IRCQueue.c - NeonServ v5.6
2 * Copyright (C) 2011-2012 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "ClientSocket.h"
19 #include "IOHandler.h"
23 #define MAXPENALTY 8 /* 4 messages */
27 struct QueueEntry *next;
31 struct ClientSocket *client;
32 struct IODescriptor *iofd;
35 struct QueueEntry *fastqueue_first, *fastqueue_last;
36 struct QueueEntry *normalqueue_first, *normalqueue_last;
37 struct QueueEntry *textqueue_first, *textqueue_last;
40 static IOHANDLER_CALLBACK(queue_callback);
42 static struct BotQueue *initialize_queue(struct ClientSocket *client) {
43 struct BotQueue *queue = malloc(sizeof(*queue));
45 printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
48 queue->client = client;
49 client->queue = queue;
52 queue->fastqueue_first = NULL;
53 queue->fastqueue_last = NULL;
54 queue->normalqueue_first = NULL;
55 queue->normalqueue_last = NULL;
56 queue->textqueue_first = NULL;
57 queue->textqueue_last = NULL;
61 static int calculate_penalty(char *message) {
62 int msglen = strlen(message);
63 int penalty = (2 + msglen / 100);
67 int queue_add(struct ClientSocket *client, char* msg, int len) {
69 client->queue = initialize_queue(client);
70 struct BotQueue *queue = client->queue;
71 char *args = strstr(msg, " ");
76 if(!stricmp(msg, "MODE"))
78 else if(!stricmp(msg, "KICK"))
80 else if(!stricmp(msg, "PONG"))
82 else if(!stricmp(msg, "PRIVMSG"))
84 else if(!stricmp(msg, "NOTICE"))
86 else if(!stricmp(msg, "WHO"))
94 //check if we need to queue
97 if(queue->textqueue_first) {
102 if(queue->normalqueue_first) {
107 if(queue->fastqueue_first) {
112 if(queue->penalty >= MAXPENALTY)
118 int penalty = calculate_penalty(msg);
119 write_socket_force(client, msg, len);
120 queue->penalty += penalty;
122 struct timeval timeout;
123 gettimeofday(&timeout, NULL);
124 if(queue->penalty >= MAXPENALTY)
125 queue->rem_penalty = (queue->penalty - MAXPENALTY)+1;
127 queue->rem_penalty = queue->penalty;
128 timeout.tv_sec += queue->rem_penalty;
129 queue->iofd = iohandler_timer(timeout, queue_callback);
130 queue->iofd->data = queue;
133 struct QueueEntry *entry = malloc(sizeof(*entry));
135 printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
138 entry->msg = strdup(msg);
140 if(type == 1) { //low priority
141 if(queue->textqueue_last) {
142 queue->textqueue_last->next = entry;
143 queue->textqueue_last = entry;
145 queue->textqueue_last = entry;
146 queue->textqueue_first = entry;
148 } else if(type == 2) { //normal priority
149 if(queue->normalqueue_last) {
150 queue->normalqueue_last->next = entry;
151 queue->normalqueue_last = entry;
153 queue->normalqueue_last = entry;
154 queue->normalqueue_first = entry;
156 } else if(type == 3) { //high priority
157 if(queue->fastqueue_last) {
158 queue->fastqueue_last->next = entry;
159 queue->fastqueue_last = entry;
161 queue->fastqueue_last = entry;
162 queue->fastqueue_first = entry;
169 static void dequeue_bot(struct ClientSocket *client) {
170 if(client->queue->penalty >= MAXPENALTY) return;
172 //try to send high priority messages
173 if(client->queue->fastqueue_first) {
175 struct QueueEntry *entry = client->queue->fastqueue_first;
177 client->queue->fastqueue_last = NULL;
178 client->queue->fastqueue_first = client->queue->fastqueue_first->next;
179 penalty = calculate_penalty(entry->msg);
180 write_socket_force(client, entry->msg, strlen(entry->msg));
181 client->queue->penalty += penalty;
184 } while(client->queue->penalty < MAXPENALTY && client->queue->fastqueue_first);
186 if(client->queue->penalty >= MAXPENALTY) return;
187 //try to send normal priority messages
188 if(client->queue->normalqueue_first) {
190 struct QueueEntry *entry = client->queue->normalqueue_first;
192 client->queue->normalqueue_last = NULL;
193 client->queue->normalqueue_first = client->queue->normalqueue_first->next;
194 penalty = calculate_penalty(entry->msg);
195 write_socket_force(client, entry->msg, strlen(entry->msg));
196 client->queue->penalty += penalty;
199 } while(client->queue->penalty < MAXPENALTY && client->queue->normalqueue_first);
201 if(client->queue->penalty >= MAXPENALTY) return;
202 //try to send low priority messages
203 if(client->queue->textqueue_first) {
205 struct QueueEntry *entry = client->queue->textqueue_first;
207 client->queue->textqueue_last = NULL;
208 client->queue->textqueue_first = client->queue->textqueue_first->next;
209 penalty = calculate_penalty(entry->msg);
210 write_socket_force(client, entry->msg, strlen(entry->msg));
211 client->queue->penalty += penalty;
214 } while(client->queue->penalty < MAXPENALTY && client->queue->textqueue_first);
218 void queue_destroy(struct ClientSocket *client) {
219 if(!client->queue) return;
220 struct QueueEntry *entry, *next;
221 for(entry = client->queue->fastqueue_first; entry; entry = next) {
226 for(entry = client->queue->normalqueue_first; entry; entry = next) {
231 for(entry = client->queue->textqueue_first; entry; entry = next) {
236 if(client->queue->iofd)
237 iohandler_close(client->queue->iofd);
239 client->queue = NULL;
242 static IOHANDLER_CALLBACK(queue_callback) {
243 struct BotQueue *queue = event->iofd->data;
244 switch(event->type) {
245 case IOEVENT_TIMEOUT:
246 queue->penalty -= queue->rem_penalty;
247 dequeue_bot(queue->client);
248 if(queue->penalty > 0) {
249 struct timeval timeout;
250 gettimeofday(&timeout, NULL);
251 if(queue->penalty >= MAXPENALTY)
252 queue->rem_penalty = (queue->penalty - MAXPENALTY)+1;
254 queue->rem_penalty = queue->penalty;
255 timeout.tv_sec += queue->rem_penalty;
256 queue->iofd = iohandler_timer(timeout, queue_callback);
257 queue->iofd->data = queue;