-/* QServer.c - NeonServ v5.4
+/* QServer.c - NeonServ v5.5
* Copyright (C) 2011-2012 Philipp Kreil (pk910)
*
* This program is free software: you can redistribute it and/or modify
#include "WHOHandler.h"
#include "ConfigParser.h"
#include "bots.h"
+#include "IOHandler.h"
#ifdef WIN32
typedef uint32_t socklen_t;
#define QSERVER_TIMEOUT 30
#define QSERVER_MAXCLIENTS 100
-#define QSERVER_FLAG_DISCONNECT 0x01
-#define QSERVER_FLAG_AUTHED 0x02
-#define QSERVER_FLAG_IN_USE 0x04
+#define QSERVER_FLAG_AUTHED 0x01
+#define QSERVER_FLAG_IN_USE 0x02
struct QServerClient {
- int sock;
+ struct IODescriptor *iofd;
unsigned int flags;
- time_t lastmsg;
- char buffer[MAXLEN];
- int bufferpos;
int references;
struct QServerClient *next;
};
-static int server_sockfd = 0;
+static struct IODescriptor *server_iofd = NULL;
struct QServerClient *qserver_clients = NULL;
static int qserver_clientcount = 0;
+static IOHANDLER_CALLBACK(qserver_callback);
+
void qserver_init() {
if(get_int_field("QServer.enabled")) {
- server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (server_sockfd < 0)
- return;
- struct sockaddr_in serv_addr;
- memset(&serv_addr, 0, sizeof(serv_addr));
- int portno = get_int_field("QServer.port");
- if(!portno)
- portno = 7499;
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = INADDR_ANY;
- serv_addr.sin_port = htons(portno);
- if (bind(server_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
- return;
- listen(server_sockfd,5);
+ char *host = get_string_field("QServer.host");
+ if(!host)
+ host = "0.0.0.0";
+ int port = get_int_field("QServer.port");
+ if(!port)
+ port = 7499;
+ server_iofd = iohandler_listen(host, port, qserver_callback);
}
}
+void qserver_free() {
+ struct QServerClient *client, *next;
+ for (client = qserver_clients; client; client = next) {
+ next = client->next;
+ if(client->iofd)
+ iohandler_close(client->iofd);
+ free(client);
+ }
+ qserver_clients = NULL;
+ qserver_clientcount = 0;
+ iohandler_close(server_iofd);
+ server_iofd = NULL;
+}
+
static int qserver_write(struct QServerClient *client, char* msg, int len) {
- if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return 0;
+ if (!client || !client->iofd) return 0;
if(!len)
len = strlen(msg);
- int ret = 1;
- #ifdef WIN32
- ret = send(client->sock, msg, len, 0);
- #else
- ret = write(client->sock, msg, len);
- #endif
- return ret;
+ iohandler_send(client->iofd, msg, len);
+ return 1;
}
static void qserver_put(struct QServerClient *client, const char *text, ...) {
va_list arg_list;
char sendBuf[MAXLEN];
int pos;
- if (!(client && !(client->flags & QSERVER_FLAG_DISCONNECT))) return;
+ if (!client || !client->iofd) return;
sendBuf[0] = '\0';
va_start(arg_list, text);
pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
qserver_write(client, sendBuf, pos+1);
}
+static void qserver_update_lastmsg(struct QServerClient *client) {
+ struct timeval timeout;
+ gettimeofday(&timeout, NULL);
+ timeout.tv_sec += QSERVER_TIMEOUT;
+ iohandler_set_timeout(client->iofd, &timeout);
+}
+
static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
if(client->flags & QSERVER_FLAG_AUTHED) {
qserver_put(client, "E :Already Authed");
return;
}
client->flags |= QSERVER_FLAG_AUTHED;
- client->lastmsg = time(0);
+ qserver_update_lastmsg(client);
qserver_put(client, "A :Logged in");
}
qserver_put(client, "E :Not Authed");\
return;\
}\
- client->lastmsg = time(0);\
+ qserver_update_lastmsg(client);\
}
static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
-static void qserver_parse(struct QServerClient *client, char *line, int len) {
+static void qserver_parse(struct QServerClient *client, char *line) {
int argc = 0;
char *argv[MAXNUMPARAMS];
while(*line) {
qserver_put(client, "E :Unknown Command");
}
-void qserver_loop() {
- if(!get_int_field("QServer.enabled"))
+static void qserver_accept(int sockfd) {
+ struct IODescriptor *client_iofd = iohandler_add(sockfd, IOTYPE_CLIENT, NULL, qserver_callback);
+ client_iofd->state = IO_CONNECTED;
+ iohandler_update(client_iofd);
+ if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
+ iohandler_printf(client_iofd, "E :Maximum QServer Connections reached");
+ iohandler_close(client_iofd);
return;
- struct timeval tv;
+ }
+ struct QServerClient *client = malloc(sizeof(*client));
+ client->iofd = client_iofd;
+ client->references = 0;
+ client->next = qserver_clients;
+ qserver_clients = client;
+ qserver_clientcount++;
+}
+
+static void qserver_cleanup() {
struct QServerClient *client, *next, *prev = NULL;
- int ret;
- time_t now = time(0);
- fd_set fds;
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- FD_ZERO(&fds);
- ret = server_sockfd;
- FD_SET(server_sockfd, &fds);
for (client = qserver_clients; client; client = next) {
next = client->next;
- if((client->flags & (QSERVER_FLAG_DISCONNECT | QSERVER_FLAG_IN_USE)) == QSERVER_FLAG_DISCONNECT) {
- close(client->sock);
+ if(client->iofd == NULL && !(client->flags & QSERVER_FLAG_IN_USE)) {
if(prev)
prev->next = client->next;
else
qserver_clients = client->next;
qserver_clientcount--;
free(client);
- continue;
- }
- prev = client;
- if(client->flags & QSERVER_FLAG_DISCONNECT) continue;
- if(now - client->lastmsg > QSERVER_TIMEOUT) {
- qserver_put(client, "E :Timeout");
- client->flags |= QSERVER_FLAG_DISCONNECT;
- continue;
- }
- FD_SET(client->sock, &fds);
- if(client->sock > ret)
- ret = client->sock;
- }
- ret = select(ret + 1, &fds, NULL, NULL, &tv);
- if(ret == 0) {
- return;
- }
- if(FD_ISSET(server_sockfd, &fds)) {
- //new connection
- struct sockaddr_in cli_addr;
- #ifdef WIN32
- int clilen;
- #else
- socklen_t clilen;
- #endif
- client = malloc(sizeof(*client));
- clilen = sizeof(cli_addr);
- client->sock = accept(server_sockfd, (struct sockaddr *) &cli_addr, &clilen);
- client->flags = 0;
- if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
- qserver_put(client, "E :Maximum QServer Connections reached");
- close(client->sock);
- free(client);
- } else {
- client->lastmsg = now;
- client->bufferpos = 0;
- client->references = 0;
- client->next = qserver_clients;
- qserver_clients = client;
- qserver_clientcount++;
- }
- }
- int bytes, i;
- char buffer[MAXLEN];
- for (client = qserver_clients; client; client = next) {
- next = client->next;
- if(FD_ISSET(client->sock, &fds)) {
- #ifdef WIN32
- bytes = recv(client->sock, buffer, sizeof(buffer), 0);
- #else
- bytes = read(client->sock, buffer, sizeof(buffer));
- #endif
- if(bytes <= 0) {
- client->flags |= QSERVER_FLAG_DISCONNECT;
- continue;
- }
- for(i = 0; i < bytes; i++) {
- if(client->bufferpos == MAXLEN-1) {
- //buffer overflow
- qserver_put(client, "E :Buffer Overflow");
- client->flags |= QSERVER_FLAG_DISCONNECT;
- break;
- }
- if(buffer[i] == '\r') continue;
- else if(buffer[i] == '\n') {
- client->buffer[client->bufferpos] = '\0';
- qserver_parse(client, client->buffer, client->bufferpos);
- client->bufferpos = 0;
- } else {
- client->buffer[client->bufferpos++] = buffer[i];
- }
- }
}
}
}
-void qserver_free() {
- struct QServerClient *client, *next;
- for (client = qserver_clients; client; client = next) {
- next = client->next;
- close(client->sock);
- free(client);
+static IOHANDLER_CALLBACK(qserver_callback) {
+ struct QServerClient *client = event->iofd->data;
+ switch(event->type) {
+ case IOEVENT_TIMEOUT:
+ qserver_put(client, "E :Timeout");
+ client->iofd = NULL;
+ break;
+ case IOEVENT_RECV:
+ qserver_parse(client, event->data.recv_str);
+ break;
+ case IOEVENT_CLOSED:
+ iohandler_close(client->iofd);
+ client->iofd = NULL;
+ break;
+ case IOEVENT_ACCEPT:
+ qserver_accept(event->data.accept_fd);
+ break;
+ default:
+ break;
}
- qserver_clients = NULL;
- qserver_clientcount = 0;
- close(server_sockfd);
+ qserver_cleanup();
}
/*