#include "ClientSocket.h"
#include "IRCParser.h"
#include "UserNode.h"
+#include "IRCQueue.h"
struct socket_list {
struct ClientSocket *data;
client->connection_time = 0;
client->botid = 0;
client->clientid = 0;
+ client->queue = NULL;
client->next = sockets->data;
sockets->data = client;
return client;
} else
last_sock = sock;
}
+ if(client->queue)
+ queue_destroy(client);
free(client->host);
free(client->pass);
free(client);
return 1;
}
-int write_socket(struct ClientSocket *client, char* msg, int len) {
- if(!(client->flags & SOCKET_FLAG_CONNECTED)) return 0;
+int write_socket_force(struct ClientSocket *client, char* msg, int len) {
printf("[send %d] %s", len, msg);
#ifdef WIN32
send(client->sock, msg, len, 0);
return 1;
}
+int write_socket(struct ClientSocket *client, char* msg, int len) {
+ if(!(client->flags & SOCKET_FLAG_CONNECTED)) return 0;
+ if(client->flags & SOCKET_FLAG_USE_QUEUE)
+ return queue_add(client, msg, len);
+ else
+ return write_socket_force(client, msg, len);
+}
+
void socket_loop(int timeout_seconds) {
if(sockets == NULL) return;
fd_set fds;
//error
sock->flags &= ~(SOCKET_FLAG_CONNECTED | SOCKET_FLAG_READY);
bot_disconnect(sock);
+ if(sock->queue)
+ queue_destroy(sock);
} else {
sock->traffic_in += bytes;
int used = parse_lines(sock, sock->buffer, sock->bufferpos);
next = client->next;
if((client->flags & SOCKET_FLAG_CONNECTED))
close(client->sock);
+ if(client->queue)
+ queue_destroy(client);
free(client->host);
free(client->pass);
free(client);
--- /dev/null
+/* IRCQueue.c - NeonServ v5.1
+ * Copyright (C) 2011 Philipp Kreil (pk910)
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#include "IRCQueue.h"
+#include "ClientSocket.h"
+
+#define MAXPENALTY 6
+
+struct QueueEntry {
+ char *msg;
+ struct QueueEntry *next;
+};
+
+struct BotQueue {
+ struct ClientSocket *client;
+ int penalty;
+ struct QueueEntry *fastqueue_first, *fastqueue_last;
+ struct QueueEntry *normalqueue_first, *normalqueue_last;
+ struct QueueEntry *textqueue_first, *textqueue_last;
+};
+
+static struct BotQueue *initialize_queue(struct ClientSocket *client) {
+ struct BotQueue *queue = malloc(sizeof(*queue));
+ if (!queue) {
+ perror("malloc() failed");
+ return NULL;
+ }
+ queue->client = client;
+ client->queue = queue;
+ queue->penalty = 0;
+ queue->fastqueue_first = NULL;
+ queue->fastqueue_last = NULL;
+ queue->normalqueue_first = NULL;
+ queue->normalqueue_last = NULL;
+ queue->textqueue_first = NULL;
+ queue->textqueue_last = NULL;
+ return queue;
+}
+
+int queue_add(struct ClientSocket *client, char* msg, int len) {
+ if(!client->queue)
+ client->queue = initialize_queue(client);
+ struct BotQueue *queue = client->queue;
+ char *args = strstr(msg, " ");
+ int type;
+ if(args) {
+ *args = '\0';
+ if(!stricmp(msg, "MODE"))
+ type = 3;
+ else if(!stricmp(msg, "KICK"))
+ type = 3;
+ else if(!stricmp(msg, "PONG"))
+ type = 3;
+ else if(!stricmp(msg, "PRIVMSG"))
+ type = 1;
+ else if(!stricmp(msg, "NOTICE"))
+ type = 1;
+ else if(!stricmp(msg, "WHO"))
+ type = 1;
+ else
+ type = 2;
+ *args = ' ';
+ } else
+ type = 2;
+ struct QueueEntry *entry = malloc(sizeof(*entry));
+ if (!entry) {
+ perror("malloc() failed");
+ return 0;
+ }
+ entry->msg = strdup(msg);
+ entry->next = NULL;
+ if(type == 1) { //low priority
+ if(queue->textqueue_last) {
+ queue->textqueue_last->next = entry;
+ queue->textqueue_last = entry;
+ } else {
+ queue->textqueue_last = entry;
+ queue->textqueue_first = entry;
+ }
+ } else if(type == 2) { //normal priority
+ if(queue->normalqueue_last) {
+ queue->normalqueue_last->next = entry;
+ queue->normalqueue_last = entry;
+ } else {
+ queue->normalqueue_last = entry;
+ queue->normalqueue_first = entry;
+ }
+ } else if(type == 3) { //high priority
+ if(queue->fastqueue_last) {
+ queue->fastqueue_last->next = entry;
+ queue->fastqueue_last = entry;
+ } else {
+ queue->fastqueue_last = entry;
+ queue->fastqueue_first = entry;
+ }
+ }
+ return 1;
+}
+
+static int calculate_penalty(char *message) {
+ int msglen = strlen(message);
+ int penalty = (2 + msglen / 100);
+ return penalty;
+}
+
+static void dequeue_bot(struct ClientSocket *client) {
+ if(client->queue->penalty >= MAXPENALTY) return;
+ int penalty;
+ //try to send high priority messages
+ if(client->queue->fastqueue_first) {
+ do {
+ struct QueueEntry *entry = client->queue->fastqueue_first;
+ if(!entry->next)
+ client->queue->fastqueue_last = NULL;
+ client->queue->fastqueue_first = client->queue->fastqueue_first->next;
+ penalty = calculate_penalty(entry->msg);
+ write_socket_force(client, entry->msg, strlen(entry->msg));
+ client->queue->penalty += penalty;
+ free(entry->msg);
+ free(entry);
+ } while(client->queue->penalty < MAXPENALTY && client->queue->fastqueue_first);
+ }
+ if(client->queue->penalty >= MAXPENALTY) return;
+ //try to send normal priority messages
+ if(client->queue->normalqueue_first) {
+ do {
+ struct QueueEntry *entry = client->queue->normalqueue_first;
+ if(!entry->next)
+ client->queue->normalqueue_last = NULL;
+ client->queue->normalqueue_first = client->queue->normalqueue_first->next;
+ penalty = calculate_penalty(entry->msg);
+ write_socket_force(client, entry->msg, strlen(entry->msg));
+ client->queue->penalty += penalty;
+ free(entry->msg);
+ free(entry);
+ } while(client->queue->penalty < MAXPENALTY && client->queue->normalqueue_first);
+ }
+ if(client->queue->penalty >= MAXPENALTY) return;
+ //try to send low priority messages
+ if(client->queue->textqueue_first) {
+ do {
+ struct QueueEntry *entry = client->queue->textqueue_first;
+ if(!entry->next)
+ client->queue->textqueue_last = NULL;
+ client->queue->textqueue_first = client->queue->textqueue_first->next;
+ penalty = calculate_penalty(entry->msg);
+ write_socket_force(client, entry->msg, strlen(entry->msg));
+ client->queue->penalty += penalty;
+ free(entry->msg);
+ free(entry);
+ } while(client->queue->penalty < MAXPENALTY && client->queue->textqueue_first);
+ }
+}
+
+void queue_destroy(struct ClientSocket *client) {
+ if(!client->queue) return;
+ struct QueueEntry *entry, *next;
+ for(entry = client->queue->fastqueue_first; entry; entry = next) {
+ next = entry->next;
+ free(entry->msg);
+ free(entry);
+ }
+ for(entry = client->queue->normalqueue_first; entry; entry = next) {
+ next = entry->next;
+ free(entry->msg);
+ free(entry);
+ }
+ for(entry = client->queue->textqueue_first; entry; entry = next) {
+ next = entry->next;
+ free(entry->msg);
+ free(entry);
+ }
+ free(client->queue);
+ client->queue = NULL;
+}
+
+static struct timeval lastloop;
+void queue_init() {
+ gettimeofday(&lastloop, NULL);
+}
+
+
+void queue_loop() {
+ struct ClientSocket *bot;
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ long mtime, seconds, useconds;
+ seconds = now.tv_sec - lastloop.tv_sec;
+ useconds = now.tv_usec - lastloop.tv_usec;
+ mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
+ int fullseconds = mtime/1000;
+ if(fullseconds) {
+ lastloop.tv_sec += fullseconds;
+ for(bot = getBots(0, NULL); bot; bot = getBots(0, bot)) {
+ if(bot->queue && bot->queue->penalty) {
+ bot->queue->penalty -= fullseconds;
+ if(bot->queue->penalty < 0)
+ bot->queue->penalty = 0;
+ }
+ }
+ }
+ for(bot = getBots(0, NULL); bot; bot = getBots(0, bot)) {
+ if(bot->queue)
+ dequeue_bot(bot);
+ }
+}