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"
22 #define MAXPENALTY 8 /* 4 messages */
26 struct QueueEntry *next;
30 struct ClientSocket *client;
31 struct IODescriptor *iofd;
34 struct QueueEntry *fastqueue_first, *fastqueue_last;
35 struct QueueEntry *normalqueue_first, *normalqueue_last;
36 struct QueueEntry *textqueue_first, *textqueue_last;
39 static IOHANDLER_CALLBACK(queue_callback);
41 static struct BotQueue *initialize_queue(struct ClientSocket *client) {
42 struct BotQueue *queue = malloc(sizeof(*queue));
44 perror("malloc() failed");
47 queue->client = client;
48 client->queue = queue;
51 queue->fastqueue_first = NULL;
52 queue->fastqueue_last = NULL;
53 queue->normalqueue_first = NULL;
54 queue->normalqueue_last = NULL;
55 queue->textqueue_first = NULL;
56 queue->textqueue_last = NULL;
60 static int calculate_penalty(char *message) {
61 int msglen = strlen(message);
62 int penalty = (2 + msglen / 100);
66 int queue_add(struct ClientSocket *client, char* msg, int len) {
68 client->queue = initialize_queue(client);
69 struct BotQueue *queue = client->queue;
70 char *args = strstr(msg, " ");
75 if(!stricmp(msg, "MODE"))
77 else if(!stricmp(msg, "KICK"))
79 else if(!stricmp(msg, "PONG"))
81 else if(!stricmp(msg, "PRIVMSG"))
83 else if(!stricmp(msg, "NOTICE"))
85 else if(!stricmp(msg, "WHO"))
93 //check if we need to queue
96 if(queue->textqueue_first) {
101 if(queue->normalqueue_first) {
106 if(queue->fastqueue_first) {
111 if(queue->penalty >= MAXPENALTY)
117 int penalty = calculate_penalty(msg);
118 write_socket_force(client, msg, len);
119 queue->penalty += penalty;
121 struct timeval timeout;
122 gettimeofday(&timeout, NULL);
123 if(queue->penalty >= MAXPENALTY)
124 queue->rem_penalty = (queue->penalty - MAXPENALTY)+1;
126 queue->rem_penalty = queue->penalty;
127 timeout.tv_sec += queue->rem_penalty;
128 queue->iofd = iohandler_timer(timeout, queue_callback);
129 queue->iofd->data = queue;
132 struct QueueEntry *entry = malloc(sizeof(*entry));
134 perror("malloc() failed");
137 entry->msg = strdup(msg);
139 if(type == 1) { //low priority
140 if(queue->textqueue_last) {
141 queue->textqueue_last->next = entry;
142 queue->textqueue_last = entry;
144 queue->textqueue_last = entry;
145 queue->textqueue_first = entry;
147 } else if(type == 2) { //normal priority
148 if(queue->normalqueue_last) {
149 queue->normalqueue_last->next = entry;
150 queue->normalqueue_last = entry;
152 queue->normalqueue_last = entry;
153 queue->normalqueue_first = entry;
155 } else if(type == 3) { //high priority
156 if(queue->fastqueue_last) {
157 queue->fastqueue_last->next = entry;
158 queue->fastqueue_last = entry;
160 queue->fastqueue_last = entry;
161 queue->fastqueue_first = entry;
168 static void dequeue_bot(struct ClientSocket *client) {
169 if(client->queue->penalty >= MAXPENALTY) return;
171 //try to send high priority messages
172 if(client->queue->fastqueue_first) {
174 struct QueueEntry *entry = client->queue->fastqueue_first;
176 client->queue->fastqueue_last = NULL;
177 client->queue->fastqueue_first = client->queue->fastqueue_first->next;
178 penalty = calculate_penalty(entry->msg);
179 write_socket_force(client, entry->msg, strlen(entry->msg));
180 client->queue->penalty += penalty;
183 } while(client->queue->penalty < MAXPENALTY && client->queue->fastqueue_first);
185 if(client->queue->penalty >= MAXPENALTY) return;
186 //try to send normal priority messages
187 if(client->queue->normalqueue_first) {
189 struct QueueEntry *entry = client->queue->normalqueue_first;
191 client->queue->normalqueue_last = NULL;
192 client->queue->normalqueue_first = client->queue->normalqueue_first->next;
193 penalty = calculate_penalty(entry->msg);
194 write_socket_force(client, entry->msg, strlen(entry->msg));
195 client->queue->penalty += penalty;
198 } while(client->queue->penalty < MAXPENALTY && client->queue->normalqueue_first);
200 if(client->queue->penalty >= MAXPENALTY) return;
201 //try to send low priority messages
202 if(client->queue->textqueue_first) {
204 struct QueueEntry *entry = client->queue->textqueue_first;
206 client->queue->textqueue_last = NULL;
207 client->queue->textqueue_first = client->queue->textqueue_first->next;
208 penalty = calculate_penalty(entry->msg);
209 write_socket_force(client, entry->msg, strlen(entry->msg));
210 client->queue->penalty += penalty;
213 } while(client->queue->penalty < MAXPENALTY && client->queue->textqueue_first);
217 void queue_destroy(struct ClientSocket *client) {
218 if(!client->queue) return;
219 struct QueueEntry *entry, *next;
220 for(entry = client->queue->fastqueue_first; entry; entry = next) {
225 for(entry = client->queue->normalqueue_first; entry; entry = next) {
230 for(entry = client->queue->textqueue_first; entry; entry = next) {
235 if(client->queue->iofd)
236 iohandler_close(client->queue->iofd);
238 client->queue = NULL;
241 static IOHANDLER_CALLBACK(queue_callback) {
242 struct BotQueue *queue = event->iofd->data;
243 switch(event->type) {
244 case IOEVENT_TIMEOUT:
245 queue->penalty -= queue->rem_penalty;
246 dequeue_bot(queue->client);
247 if(queue->penalty > 0) {
248 struct timeval timeout;
249 gettimeofday(&timeout, NULL);
250 if(queue->penalty >= MAXPENALTY)
251 queue->rem_penalty = (queue->penalty - MAXPENALTY)+1;
253 queue->rem_penalty = queue->penalty;
254 timeout.tv_sec += queue->rem_penalty;
255 queue->iofd = iohandler_timer(timeout, queue_callback);
256 queue->iofd->data = queue;