modified code to use IOHandler functions instead of own ones
[NeonServV5.git] / src / QServer.c
index 2d77a6b2e92c2fcb837d5597141436d8c59db03d..1e112332bbf1bed146797caf7ccd1a90fd705543 100644 (file)
@@ -24,6 +24,7 @@
 #include "WHOHandler.h"
 #include "ConfigParser.h"
 #include "bots.h"
+#include "IOHandler.h"
 
 #ifdef WIN32
 typedef uint32_t socklen_t;
@@ -32,54 +33,54 @@ 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));
+        char *host = get_string_field("QServer.host");
+        if(!host)
+            host = "0.0.0.0";
         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);
+        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, ...) {
@@ -97,6 +98,13 @@ static void qserver_put(struct QServerClient *client, const char *text, ...) {
     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");
@@ -111,7 +119,7 @@ static void qserver_parse_A(struct QServerClient *client, char **argv, int argc)
         return;
     }
     client->flags |= QSERVER_FLAG_AUTHED;
-    client->lastmsg = time(0);
+    qserver_update_lastmsg(client);
     qserver_put(client, "A :Logged in");
 }
 
@@ -120,7 +128,7 @@ static void qserver_parse_A(struct QServerClient *client, char **argv, int argc)
         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);
@@ -129,7 +137,7 @@ static void qserver_parse_AC(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) {
@@ -163,115 +171,59 @@ static void qserver_parse(struct QServerClient *client, char *line, int len) {
         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:
+        
+        break;
+    default:
+        break;
     }
-    qserver_clients = NULL;
-    qserver_clientcount = 0;
-    close(server_sockfd);
+    qserver_cleanup();
 }
 
 /*