1 /* IRCQueue.c - NeonServ v5.5
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"
21 #define MAXPENALTY 8 /* 4 messages */
25 struct QueueEntry *next;
29 struct ClientSocket *client;
30 struct IODescriptor *iofd;
33 struct QueueEntry *fastqueue_first, *fastqueue_last;
34 struct QueueEntry *normalqueue_first, *normalqueue_last;
35 struct QueueEntry *textqueue_first, *textqueue_last;
38 static IOHANDLER_CALLBACK(queue_callback);
40 static struct BotQueue *initialize_queue(struct ClientSocket *client) {
41 struct BotQueue *queue = malloc(sizeof(*queue));
43 perror("malloc() failed");
46 queue->client = client;
47 client->queue = queue;
49 queue->fastqueue_first = NULL;
50 queue->fastqueue_last = NULL;
51 queue->normalqueue_first = NULL;
52 queue->normalqueue_last = NULL;
53 queue->textqueue_first = NULL;
54 queue->textqueue_last = NULL;
58 int queue_add(struct ClientSocket *client, char* msg, int len) {
60 client->queue = initialize_queue(client);
61 struct BotQueue *queue = client->queue;
62 char *args = strstr(msg, " ");
67 if(!stricmp(msg, "MODE"))
69 else if(!stricmp(msg, "KICK"))
71 else if(!stricmp(msg, "PONG"))
73 else if(!stricmp(msg, "PRIVMSG"))
75 else if(!stricmp(msg, "NOTICE"))
77 else if(!stricmp(msg, "WHO"))
85 //check if we need to queue
88 if(queue->textqueue_first) {
93 if(queue->normalqueue_first) {
98 if(queue->fastqueue_first) {
103 if(queue->penalty >= MAXPENALTY)
109 int penalty = calculate_penalty(msg);
110 write_socket_force(client, msg, len);
111 queue->penalty += penalty;
113 struct timeval timeout;
114 gettimeofday(&timeout, NULL);
115 queue->rem_penalty = (MAXPENALTY - queue->penalty) + 1;
116 timeout.tv_sec += queue->rem_penalty;
117 queue->iofd = iohandler_timer(timeout, queue_callback);
120 struct QueueEntry *entry = malloc(sizeof(*entry));
122 perror("malloc() failed");
125 entry->msg = strdup(msg);
127 if(type == 1) { //low priority
128 if(queue->textqueue_last) {
129 queue->textqueue_last->next = entry;
130 queue->textqueue_last = entry;
132 queue->textqueue_last = entry;
133 queue->textqueue_first = entry;
135 } else if(type == 2) { //normal priority
136 if(queue->normalqueue_last) {
137 queue->normalqueue_last->next = entry;
138 queue->normalqueue_last = entry;
140 queue->normalqueue_last = entry;
141 queue->normalqueue_first = entry;
143 } else if(type == 3) { //high priority
144 if(queue->fastqueue_last) {
145 queue->fastqueue_last->next = entry;
146 queue->fastqueue_last = entry;
148 queue->fastqueue_last = entry;
149 queue->fastqueue_first = entry;
156 static int calculate_penalty(char *message) {
157 int msglen = strlen(message);
158 int penalty = (2 + msglen / 100);
162 static void dequeue_bot(struct ClientSocket *client) {
163 if(client->queue->penalty >= MAXPENALTY) return;
165 //try to send high priority messages
166 if(client->queue->fastqueue_first) {
168 struct QueueEntry *entry = client->queue->fastqueue_first;
170 client->queue->fastqueue_last = NULL;
171 client->queue->fastqueue_first = client->queue->fastqueue_first->next;
172 penalty = calculate_penalty(entry->msg);
173 write_socket_force(client, entry->msg, strlen(entry->msg));
174 client->queue->penalty += penalty;
177 } while(client->queue->penalty < MAXPENALTY && client->queue->fastqueue_first);
179 if(client->queue->penalty >= MAXPENALTY) return;
180 //try to send normal priority messages
181 if(client->queue->normalqueue_first) {
183 struct QueueEntry *entry = client->queue->normalqueue_first;
185 client->queue->normalqueue_last = NULL;
186 client->queue->normalqueue_first = client->queue->normalqueue_first->next;
187 penalty = calculate_penalty(entry->msg);
188 write_socket_force(client, entry->msg, strlen(entry->msg));
189 client->queue->penalty += penalty;
192 } while(client->queue->penalty < MAXPENALTY && client->queue->normalqueue_first);
194 if(client->queue->penalty >= MAXPENALTY) return;
195 //try to send low priority messages
196 if(client->queue->textqueue_first) {
198 struct QueueEntry *entry = client->queue->textqueue_first;
200 client->queue->textqueue_last = NULL;
201 client->queue->textqueue_first = client->queue->textqueue_first->next;
202 penalty = calculate_penalty(entry->msg);
203 write_socket_force(client, entry->msg, strlen(entry->msg));
204 client->queue->penalty += penalty;
207 } while(client->queue->penalty < MAXPENALTY && client->queue->textqueue_first);
211 void queue_destroy(struct ClientSocket *client) {
212 if(!client->queue) return;
213 struct QueueEntry *entry, *next;
214 for(entry = client->queue->fastqueue_first; entry; entry = next) {
219 for(entry = client->queue->normalqueue_first; entry; entry = next) {
224 for(entry = client->queue->textqueue_first; entry; entry = next) {
229 if(client->queue->iofd)
230 iohandler_close(client->queue->iofd);
232 client->queue = NULL;
235 static IOHANDLER_CALLBACK(queue_callback) {
236 struct BotQueue *queue = event->iofd->data;
237 switch(event->type) {
238 case IOEVENT_TIMEOUT:
239 queue->penalty -= queue->rem_penalty;
240 dequeue_bot(queue->client);
241 if(queue->penalty > 0) {
242 struct timeval timeout;
243 gettimeofday(&timeout, NULL);
244 queue->rem_penalty = (MAXPENALTY - queue->penalty) + 1;
245 timeout.tv_sec += queue->rem_penalty;
246 queue->iofd = iohandler_timer(timeout, queue_callback);