From: Michael Poole Date: Fri, 22 Sep 2006 02:51:50 +0000 (+0000) Subject: Add direct query server module. X-Git-Tag: v1.4.0-rc1~116 X-Git-Url: http://git.pk910.de/?p=srvx.git;a=commitdiff_plain;h=e0520732f1170797ecede546e346fea23c124d03 Add direct query server module. 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 --- diff --git a/ChangeLog b/ChangeLog index c9690b3..2f916a3 100644 --- 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 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 patch-39 Summary: diff --git a/src/Makefile.am b/src/Makefile.am index 290d948..540b48b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000..678846d --- /dev/null +++ b/src/mod-qserver.c @@ -0,0 +1,224 @@ +/* Direct Query Server module for srvx 1.x + * Copyright 2006 Michael Poole + * + * 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 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; +} diff --git a/srvx.conf.example b/srvx.conf.example index 6b89f32..e8ca75a 100644 --- a/srvx.conf.example +++ b/srvx.conf.example @@ -292,6 +292,11 @@ "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" {