pissircd/src/proc_io_server.c

192 lines
6.1 KiB
C

/************************************************************************
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/proc_io_server.c
* (c) 2022- Bram Matthys and The UnrealIRCd team
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* 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 1, 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file
* @brief Inter-process I/O
*/
#include "unrealircd.h"
#include <ares.h>
/* Forward declarations */
CMD_FUNC(procio_status);
CMD_FUNC(procio_modules);
CMD_FUNC(procio_rehash);
CMD_FUNC(procio_exit);
CMD_FUNC(procio_help);
void start_of_control_client_handshake(Client *client);
int procio_accept(Client *client);
/** Create the unrealircd.ctl socket (server-side) */
void add_proc_io_server(void)
{
ConfigItem_listen *listener;
#ifdef _WIN32
/* Ignore silently on Windows versions older than W10 build 17061 */
if (!unix_sockets_capable())
return;
#endif
listener = safe_alloc(sizeof(ConfigItem_listen));
safe_strdup(listener->file, CONTROLFILE);
listener->socket_type = SOCKET_TYPE_UNIX;
listener->options = LISTENER_CONTROL|LISTENER_NO_CHECK_CONNECT_FLOOD|LISTENER_NO_CHECK_ZLINED;
listener->start_handshake = start_of_control_client_handshake;
listener->fd = -1;
AddListItem(listener, conf_listen);
if (add_listener(listener) == -1)
exit(-1);
CommandAdd(NULL, "STATUS", procio_status, MAXPARA, CMD_CONTROL);
CommandAdd(NULL, "MODULES", procio_modules, MAXPARA, CMD_CONTROL);
CommandAdd(NULL, "REHASH", procio_rehash, MAXPARA, CMD_CONTROL);
CommandAdd(NULL, "EXIT", procio_exit, MAXPARA, CMD_CONTROL);
CommandAdd(NULL, "HELP", procio_help, MAXPARA, CMD_CONTROL);
HookAdd(NULL, HOOKTYPE_ACCEPT, -1000000, procio_accept);
}
int procio_accept(Client *client)
{
if (client->local->listener->options & LISTENER_CONTROL)
{
irccounts.unknown--;
client->status = CLIENT_STATUS_CONTROL;
list_del(&client->lclient_node);
list_add(&client->lclient_node, &control_list);
}
return 0;
}
/** Start of "control channel" client handshake - this is minimal
* @param client The client
*/
void start_of_control_client_handshake(Client *client)
{
sendto_one(client, NULL, "READY %s %s", me.name, version);
fd_setselect(client->local->fd, FD_SELECT_READ, read_packet, client);
}
CMD_FUNC(procio_status)
{
sendto_one(client, NULL, "REPLY servername %s", me.name);
sendto_one(client, NULL, "REPLY unrealircd_version %s", version);
sendto_one(client, NULL, "REPLY libssl_version %s", SSLeay_version(SSLEAY_VERSION));
sendto_one(client, NULL, "REPLY libsodium_version %s", sodium_version_string());
#ifdef USE_LIBCURL
sendto_one(client, NULL, "REPLY libcurl_version %s", curl_version());
#endif
sendto_one(client, NULL, "REPLY libcares_version %s", ares_version(NULL));
sendto_one(client, NULL, "REPLY libpcre2_version %s", pcre2_version());
#if JANSSON_VERSION_HEX >= 0x020D00
sendto_one(client, NULL, "REPLY libjansson %s\n", jansson_version_str());
#endif
sendto_one(client, NULL, "REPLY global_clients %ld", (long)irccounts.clients);
sendto_one(client, NULL, "REPLY local_clients %ld", (long)irccounts.me_clients);
sendto_one(client, NULL, "REPLY operators %ld", (long)irccounts.operators);
sendto_one(client, NULL, "REPLY servers %ld", (long)irccounts.servers);
sendto_one(client, NULL, "REPLY channels %ld", (long)irccounts.channels);
sendto_one(client, NULL, "END 0");
}
extern MODVAR Module *Modules;
CMD_FUNC(procio_modules)
{
char tmp[1024];
Module *m;
for (m = Modules; m; m = m->next)
{
tmp[0] = '\0';
if (m->flags & MODFLAG_DELAYED)
strlcat(tmp, "[Unloading] ", sizeof(tmp));
if (m->options & MOD_OPT_PERM_RELOADABLE)
strlcat(tmp, "[PERM-BUT-RELOADABLE] ", sizeof(tmp));
if (m->options & MOD_OPT_PERM)
strlcat(tmp, "[PERM] ", sizeof(tmp));
if (!(m->options & MOD_OPT_OFFICIAL))
strlcat(tmp, "[3RD] ", sizeof(tmp));
sendto_one(client, NULL, "REPLY %s %s - %s - by %s %s",
m->header->name,
m->header->version,
m->header->description,
m->header->author,
tmp);
}
sendto_one(client, NULL, "END 0");
}
CMD_FUNC(procio_rehash)
{
if (loop.rehashing)
{
sendto_one(client, NULL, "REPLY ERROR: A rehash is already in progress");
sendto_one(client, NULL, "END 1");
return;
}
if (parv[1] && !strcmp(parv[1], "-tls"))
{
int ret;
SetMonitorRehash(client);
unreal_log(ULOG_INFO, "config", "CONFIG_RELOAD_TLS", NULL, "Reloading all TLS related data (./unrealircd reloadtls)");
ret = reinit_tls();
sendto_one(client, NULL, "END %d", ret == 0 ? -1 : 0);
ClearMonitorRehash(client);
} else {
SetMonitorRehash(client);
unreal_log(ULOG_INFO, "config", "CONFIG_RELOAD", client, "Rehashing server configuration file [./unrealircd rehash]");
request_rehash(client);
/* completion will go via procio_post_rehash() */
}
}
CMD_FUNC(procio_exit)
{
sendto_one(client, NULL, "END 0");
exit_client(client, NULL, "");
}
CMD_FUNC(procio_help)
{
sendto_one(client, NULL, "REPLY Commands available:");
sendto_one(client, NULL, "REPLY EXIT");
sendto_one(client, NULL, "REPLY HELP");
sendto_one(client, NULL, "REPLY REHASH");
sendto_one(client, NULL, "REPLY STATUS");
sendto_one(client, NULL, "REPLY MODULES");
sendto_one(client, NULL, "END 0");
}
/** Called upon REHASH completion (with or without failure) */
void procio_post_rehash(int failure)
{
Client *client;
list_for_each_entry(client, &control_list, lclient_node)
{
if (IsMonitorRehash(client))
{
sendto_one(client, NULL, "END %d", failure);
ClearMonitorRehash(client);
}
}
}