Add direct query server module.
authorMichael Poole <mdpoole@troilus.org>
Fri, 22 Sep 2006 02:51:50 +0000 (02:51 +0000)
committerMichael Poole <mdpoole@troilus.org>
Fri, 22 Sep 2006 02:51:50 +0000 (02:51 +0000)
srvx.conf.example: Document qserver configuration.

src/Makefile.am (EXTRA_srvx_SOURCES): Add mod-qserver.c.

src/mod-qserver.c: New file.
git-archimport-id: srvx@srvx.net--2006/srvx--devo--1.3--patch-40

ChangeLog
src/Makefile.am
src/mod-qserver.c [new file with mode: 0644]
srvx.conf.example

index c9690b3df92ac0ffec04088c41e59b3f6a65db75..2f916a3d7d8cd6d71373dfbf5add553179bc9b97 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,26 @@
 # arch-tag: automatic-ChangeLog--srvx@srvx.net--2006/srvx--devo--1.3
 #
 
+2006-09-22 02:51:50 GMT        Michael Poole <mdpoole@troilus.org>     patch-40
+
+    Summary:
+      Add direct query server module.
+    Revision:
+      srvx--devo--1.3--patch-40
+
+    srvx.conf.example: Document qserver configuration.
+    
+    src/Makefile.am (EXTRA_srvx_SOURCES): Add mod-qserver.c.
+    
+    src/mod-qserver.c: New file.
+
+    new files:
+     src/.arch-ids/mod-qserver.c.id src/mod-qserver.c
+
+    modified files:
+     ChangeLog src/Makefile.am src/ioset-epoll.c srvx.conf.example
+
+
 2006-09-22 02:45:20 GMT        Michael Poole <mdpoole@troilus.org>     patch-39
 
     Summary:
index 290d948c0a03ef56f794102d795c5e4fbdbd31a9..540b48bcf7d373a9b433996c05e033ee199816fc 100644 (file)
@@ -45,6 +45,7 @@ EXTRA_srvx_SOURCES = \
        mod-snoop.c \
        mod-memoserv.c \
        mod-helpserv.c \
+       mod-qserver.c \
        mod-sockcheck.c
 srvx_LDADD = @MODULE_OBJS@
 srvx_DEPENDENCIES = @MODULE_OBJS@
diff --git a/src/mod-qserver.c b/src/mod-qserver.c
new file mode 100644 (file)
index 0000000..678846d
--- /dev/null
@@ -0,0 +1,224 @@
+/* Direct Query Server module for srvx 1.x
+ * Copyright 2006 Michael Poole <mdpoole@troilus.org>
+ *
+ * This is PROPRIETARY, UNPUBLISHED code.
+ *
+ * This file is not part of srvx. The only logical reason for you to have
+ * this file is to be working for GameSurge.
+ *
+ * If this is not the case, you should delete this copy and inform
+ * Michael Poole <mdpoole@troilus.org> where you acquired it.
+ *
+ * The copyright notice above is not evidence that this code is, has been,
+ * or ever will be publicly licensed.
+ */
+
+#include "conf.h"
+#include "hash.h"
+#include "ioset.h"
+#include "log.h"
+#include "modcmd.h"
+#include "proto.h"
+
+const char *qserver_module_deps[] = { NULL };
+
+struct qserverClient {
+    struct userNode *user;
+    struct io_fd *fd;
+    unsigned int id;
+    unsigned int password_ok : 1;
+};
+
+static struct log_type *qserver_log;
+static struct io_fd *qserver_listener;
+static struct qserverClient **qserver_clients;
+static dict_t qserver_dict;
+static unsigned int qserver_nbots;
+
+static struct {
+    const char *password;
+} conf;
+
+static void
+qserver_privmsg(struct userNode *user, struct userNode *target, const char *text, UNUSED_ARG(int server_qualified))
+{
+    struct qserverClient *client;
+
+    client = dict_find(qserver_dict, target->nick, NULL);
+    assert(client->user == target);
+    ioset_printf(client->fd, "%s P :%s\n", user->nick, text);
+}
+
+static void
+qserver_notice(struct userNode *user, struct userNode *target, const char *text, UNUSED_ARG(int server_qualified))
+{
+    struct qserverClient *client;
+
+    client = dict_find(qserver_dict, target->nick, NULL);
+    assert(client->user == target);
+    ioset_printf(client->fd, "%s N :%s\n", user->nick, text);
+}
+
+static void
+qserver_readable(struct io_fd *fd)
+{
+    struct qserverClient *client;
+    struct service *service;
+    char *argv[MAXNUMPARAMS];
+    unsigned int argc;
+    size_t len;
+    int res;
+    char tmpline[MAXLEN];
+
+    client = fd->data;
+    assert(client->fd == fd);
+    res = ioset_line_read(fd, tmpline, sizeof(tmpline));
+    if (res < 0)
+        return;
+    else if (res == 0) {
+        ioset_close(fd, 1);
+        return;
+    }
+    len = strlen(tmpline);
+    while (tmpline[len - 1] == '\r' || tmpline[len - 1] == '\n')
+        tmpline[--len] = '\0';
+    argc = split_line(tmpline, false, ArrayLength(argv), argv);
+    if (argc < 3) {
+        ioset_printf(fd, "MISSING_ARGS");
+        return;
+    }
+    if (!strcmp(argv[1], "PASS")
+        && conf.password
+        && !strcmp(argv[2], conf.password)) {
+        client->password_ok = 1;
+    } else if ((client->password_ok || !conf.password)
+               && (service = service_find(argv[1])) != NULL) {
+        ioset_printf(fd, "%s S\n", argv[0]);
+        svccmd_invoke_argv(client->user, service, NULL, argc - 2, argv + 2, 1);
+        ioset_printf(fd, "%s E\n", argv[0]);
+    } else {
+        ioset_printf(fd, "%s X %s\n", argv[0], argv[1]);
+    }
+}
+
+static void
+qserver_destroy_fd(struct io_fd *fd)
+{
+    struct qserverClient *client;
+
+    client = fd->data;
+    assert(client->fd == fd);
+    dict_remove(qserver_dict, client->user->nick);
+    DelUser(client->user, NULL, 0, "client disconnected");
+    qserver_clients[client->id] = NULL;
+    free(client);
+}
+
+static void
+qserver_accept(UNUSED_ARG(struct io_fd *listener), struct io_fd *fd)
+{
+    struct qserverClient *client;
+    struct sockaddr_storage ss;
+    socklen_t sa_len;
+    unsigned int ii;
+    unsigned int jj;
+    int res;
+    char nick[NICKLEN+1];
+    char host[HOSTLEN+1];
+    char ip[HOSTLEN+1];
+
+    client = calloc(1, sizeof(*client));
+    fd->data = client;
+    fd->wants_reads = 1;
+    fd->line_reads = 1;
+    fd->readable_cb = qserver_readable;
+    fd->destroy_cb = qserver_destroy_fd;
+
+    for (ii = 0; ii < qserver_nbots; ++ii)
+        if (qserver_clients[ii] == NULL)
+            break;
+    if (ii == qserver_nbots) {
+        qserver_nbots += 8;
+        qserver_clients = realloc(qserver_clients, qserver_nbots * sizeof(qserver_clients[0]));
+        for (jj = ii; jj < qserver_nbots; ++jj)
+            qserver_clients[jj] = NULL;
+    }
+    client->id = ii;
+    client->fd = fd;
+    qserver_clients[client->id] = client;
+    snprintf(nick, sizeof(nick), " QServ%04d", client->id);
+    safestrncpy(host, "srvx.dummy.user", sizeof(host));
+    safestrncpy(ip, "0.0.0.0", sizeof(ip));
+    sa_len = sizeof(ss);
+    res = getpeername(fd->fd, (struct sockaddr*)&ss, &sa_len);
+    if (res == 0) {
+        getnameinfo((struct sockaddr*)&ss, sa_len, ip, sizeof(host), NULL, 0, NI_NUMERICHOST);
+        if (getnameinfo((struct sockaddr*)&ss, sa_len, host, sizeof(host), NULL, 0, 0) != 0)
+            safestrncpy(host, ip, sizeof(host));
+    }
+    client->user = AddLocalUser(nick, nick+1, host, "qserver dummy user", "*+i");
+    irc_pton(&client->user->ip, NULL, ip);
+    dict_insert(qserver_dict, client->user->nick, client);
+
+    reg_privmsg_func(client->user, qserver_privmsg);
+    reg_notice_func(client->user, qserver_notice);
+}
+
+static void
+qserver_conf_read(void)
+{
+    struct addrinfo hints;
+    struct addrinfo *ai;
+    dict_t node;
+    const char *str1;
+    const char *str2;
+    int res;
+
+    ioset_close(qserver_listener, 1);
+    qserver_listener = NULL;
+    node = conf_get_data("modules/qserver", RECDB_OBJECT);
+    if (!node)
+        return;
+    str1 = database_get_data(node, "address", RECDB_QSTRING);
+    str2 = database_get_data(node, "port", RECDB_QSTRING);
+    if (!str2)
+        return;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_PASSIVE;
+    hints.ai_socktype = SOCK_STREAM;
+    res = getaddrinfo(str1, str2, &hints, &ai);
+    if (res) {
+        log_module(qserver_log, LOG_ERROR, "Unable to find address [%s]:%s: %s", str1 ? str1 : "", str2, gai_strerror(res));
+    } else if (!(qserver_listener = ioset_listen(ai->ai_addr, ai->ai_addrlen, NULL, qserver_accept))) {
+        log_module(qserver_log, LOG_ERROR, "Unable to listen on [%s]:%s", str1 ? str1 : "", str2);
+    }
+    conf.password = database_get_data(node, "password", RECDB_QSTRING);
+    freeaddrinfo(ai);
+}
+
+void
+qserver_cleanup(void)
+{
+    unsigned int ii;
+
+    for (ii = 0; ii < qserver_nbots; ++ii)
+        if (qserver_clients[ii])
+            DelUser(qserver_clients[ii]->user, NULL, 0, "module finalizing");
+    dict_delete(qserver_dict);
+}
+
+int
+qserver_init(void)
+{
+    qserver_log = log_register_type("QServer", "file:qserver.log");
+    conf_register_reload(qserver_conf_read);
+    qserver_dict = dict_new();
+    reg_exit_func(qserver_cleanup);
+    return 1;
+}
+
+int
+qserver_finalize(void)
+{
+    return 1;
+}
index 6b89f32f8d9192343c54fb24072ea5dd97145563..e8ca75a4369a67f326561e382f0cc4c852a837ff 100644 (file)
         "message_expiry" "30d"; // age when messages are deleted; set
                                 // to 0 to disable message expiration
     };
+    "qserver" {
+        "address" "127.0.0.1";
+        "port" "7702";
+        "password" "hello";
+    };
 };
 
 "policers" {