Merge branch 'systemd'
* systemd: ngircd.sock: explicitely bind to IPv4 and IPv6 addresses Show address and port of sockets passed-in by systemd(8) Check type of sockets passed-in by systemd(8) Adjust severity levels of some log messages New configuration option "IdleTimeout": exit daemon when idle Implement support for systemd(8) "socket activation" contrib/README: add more files
This commit is contained in:
commit
628c14d656
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
# ngIRCd -- The Next Generation IRC Daemon
|
||||
# Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors
|
||||
# Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors
|
||||
#
|
||||
# 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
|
||||
|
@ -17,6 +17,7 @@ EXTRA_DIST = README \
|
|||
ngIRCd-Logo.gif \
|
||||
ngircd-redhat.init \
|
||||
ngircd.service \
|
||||
ngircd.socket \
|
||||
ngircd.spec \
|
||||
platformtest.sh \
|
||||
systrace.policy
|
||||
|
|
|
@ -2,18 +2,21 @@
|
|||
ngIRCd - Next Generation IRC Server
|
||||
http://ngircd.barton.de/
|
||||
|
||||
(c)2001-2011 Alexander Barton and Contributors.
|
||||
(c)2001-2013 Alexander Barton and Contributors.
|
||||
ngIRCd is free software and published under the
|
||||
terms of the GNU General Public License.
|
||||
|
||||
-- Contributions --
|
||||
-- Contributions --
|
||||
|
||||
|
||||
Debian/
|
||||
- Various files for building Debian GNU/Linux packages (".deb's").
|
||||
- ngircd.init; ngircd.default: init script for Debian-based systems.
|
||||
- ngircd.pam: example PAM configuraton.
|
||||
|
||||
MacOSX/
|
||||
- Project files for XCode, the "project builder" of Apple Mac OS X.
|
||||
- de.barton.ngircd.plist[.tmpl]: launchd(8) property list.
|
||||
|
||||
ngindent
|
||||
- Script to indent the code of ngIRCd in the "standard way".
|
||||
|
@ -24,6 +27,12 @@ ngircd-bsd.sh
|
|||
ngircd-redhat.init
|
||||
- Start/stop script for RedHat-based distributions (like CentOS).
|
||||
|
||||
ngircd.service
|
||||
- systemd(8) service unit configuration file.
|
||||
|
||||
ngircd.socket
|
||||
- systemd(8) socket unit configuration file for "socket activation".
|
||||
|
||||
ngircd.spec
|
||||
- RPM "spec" file.
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=Next Generation IRC Daemon (Socket)
|
||||
|
||||
[Socket]
|
||||
BindIPv6Only=ipv6-only
|
||||
ListenStream=0.0.0.0:6667
|
||||
#ListenStream=[::]:6667
|
||||
IPTOS=low-delay
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
|
@ -88,6 +88,13 @@
|
|||
# to not yet (or no longer) connected servers.
|
||||
;ConnectRetry = 60
|
||||
|
||||
# Number of seconds after which the whole daemon should shutdown when
|
||||
# no connections are left active after handling at least one client
|
||||
# (0: never, which is the default).
|
||||
# This can be useful for testing or when ngIRCd is started using
|
||||
# "socket activation" with systemd(8), for example.
|
||||
;IdleTimeout = 0
|
||||
|
||||
# Maximum number of simultaneous in- and outbound connections the
|
||||
# server is allowed to accept (0: unlimited):
|
||||
;MaxConnections = 0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.\"
|
||||
.\" ngircd.conf(5) manual page template
|
||||
.\"
|
||||
.TH ngircd.conf 5 "Nov 2012" ngIRCd "ngIRCd Manual"
|
||||
.TH ngircd.conf 5 "Feb 2013" ngIRCd "ngIRCd Manual"
|
||||
.SH NAME
|
||||
ngircd.conf \- configuration file of ngIRCd
|
||||
.SH SYNOPSIS
|
||||
|
@ -170,6 +170,12 @@ should be safe, but it is wise to double-check :-)
|
|||
The server tries every <ConnectRetry> seconds to establish a link to not yet
|
||||
(or no longer) connected servers. Default: 60.
|
||||
.TP
|
||||
\fBIdleTimeout\fR (number)
|
||||
Number of seconds after which the whole daemon should shutdown when no
|
||||
connections are left active after handling at least one client (0: never). This
|
||||
can be useful for testing or when ngIRCd is started using "socket activation"
|
||||
with systemd(8), for example. Default: 0.
|
||||
.TP
|
||||
\fBMaxConnections\fR (number)
|
||||
Maximum number of simultaneous in- and outbound connections the server is
|
||||
allowed to accept (0: unlimited). Default: 0.
|
||||
|
|
|
@ -370,6 +370,7 @@ Conf_Test( void )
|
|||
|
||||
puts("[LIMITS]");
|
||||
printf(" ConnectRetry = %d\n", Conf_ConnectRetry);
|
||||
printf(" IdleTimeout = %d\n", Conf_IdleTimeout);
|
||||
printf(" MaxConnections = %d\n", Conf_MaxConnections);
|
||||
printf(" MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
|
||||
printf(" MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1);
|
||||
|
@ -736,6 +737,7 @@ Set_Defaults(bool InitServers)
|
|||
|
||||
/* Limits */
|
||||
Conf_ConnectRetry = 60;
|
||||
Conf_IdleTimeout = 0;
|
||||
Conf_MaxConnections = 0;
|
||||
Conf_MaxConnectionsIP = 5;
|
||||
Conf_MaxJoins = 10;
|
||||
|
@ -830,8 +832,8 @@ Read_TextFile(const char *Filename, const char *Name, array *Destination)
|
|||
|
||||
fp = fopen(Filename, "r");
|
||||
if (!fp) {
|
||||
Config_Error(LOG_WARNING, "Can't read %s file \"%s\": %s",
|
||||
Name, Filename, strerror(errno));
|
||||
Config_Error(LOG_ERR, "Can't read %s file \"%s\": %s",
|
||||
Name, Filename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -841,7 +843,7 @@ Read_TextFile(const char *Filename, const char *Name, array *Destination)
|
|||
|
||||
/* add text including \0 */
|
||||
if (!array_catb(Destination, line, strlen(line) + 1)) {
|
||||
Log(LOG_WARNING, "Cannot read/add \"%s\", line %d: %s",
|
||||
Log(LOG_ERR, "Cannot read/add \"%s\", line %d: %s",
|
||||
Filename, line_no, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
@ -1241,6 +1243,7 @@ CheckLegacyGlobalOption(int Line, char *Var, char *Arg)
|
|||
return "[Options]";
|
||||
}
|
||||
if (strcasecmp(Var, "ConnectRetry") == 0
|
||||
|| strcasecmp(Var, "IdleTimeout") == 0
|
||||
|| strcasecmp(Var, "MaxConnections") == 0
|
||||
|| strcasecmp(Var, "MaxConnectionsIP") == 0
|
||||
|| strcasecmp(Var, "MaxJoins") == 0
|
||||
|
@ -1490,6 +1493,12 @@ Handle_LIMITS(int Line, char *Var, char *Arg)
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(Var, "IdleTimeout") == 0) {
|
||||
Conf_IdleTimeout = atoi(Arg);
|
||||
if (!Conf_IdleTimeout && strcmp(Arg, "0"))
|
||||
Config_Error_NaN(Line, Var);
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(Var, "MaxConnections") == 0) {
|
||||
Conf_MaxConnections = atoi(Arg);
|
||||
if (!Conf_MaxConnections && strcmp(Arg, "0"))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* ngIRCd -- The Next Generation IRC Daemon
|
||||
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
|
||||
* Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
|
||||
*
|
||||
* 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
|
||||
|
@ -211,6 +211,9 @@ GLOBAL bool Conf_ConnectIPv6;
|
|||
/** Try to connect to remote systems using the IPv4 protocol (true) */
|
||||
GLOBAL bool Conf_ConnectIPv4;
|
||||
|
||||
/** Idle timout (seconds), after which the daemon should exit */
|
||||
GLOBAL int Conf_IdleTimeout;
|
||||
|
||||
/** Maximum number of simultaneous connections to this server */
|
||||
GLOBAL int Conf_MaxConnections;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* ngIRCd -- The Next Generation IRC Daemon
|
||||
* Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
|
||||
* Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
|
||||
*
|
||||
* 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
|
||||
|
@ -82,6 +82,8 @@
|
|||
#define MAX_COMMANDS_SERVER_MIN 10
|
||||
#define MAX_COMMANDS_SERVICE 10
|
||||
|
||||
#define SD_LISTEN_FDS_START 3
|
||||
|
||||
|
||||
static bool Handle_Write PARAMS(( CONN_ID Idx ));
|
||||
static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
|
||||
|
@ -119,6 +121,42 @@ static void cb_Read_Resolver_Result PARAMS((int sock, UNUSED short what));
|
|||
static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what));
|
||||
static void cb_clientserver PARAMS((int sock, short what));
|
||||
|
||||
time_t idle_t = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Get number of sockets available from systemd(8).
|
||||
*
|
||||
* ngIRCd needs to implement its own sd_listen_fds(3) function and can't
|
||||
* use the one provided by systemd itself, becaus the sockets will be
|
||||
* used in a forked child process with a new PID, and this would trigger
|
||||
* an error in the standard implementation.
|
||||
*
|
||||
* @return Number of sockets available, -1 if sockets have already been
|
||||
* initialized, or 0 when no sockets have been passed.
|
||||
*/
|
||||
static int
|
||||
my_sd_listen_fds(void)
|
||||
{
|
||||
const char *e;
|
||||
long count;
|
||||
|
||||
/* Check if LISTEN_PID exists; but we ignore the result, because
|
||||
* normally ngircd forks a child before checking this, and therefore
|
||||
* the PID set in the environment is always wrong ... */
|
||||
e = getenv("LISTEN_PID");
|
||||
if (!e || !*e)
|
||||
return 0;
|
||||
|
||||
e = getenv("LISTEN_FDS");
|
||||
if (!e || !*e)
|
||||
return -1;
|
||||
count = atol(e);
|
||||
unsetenv("LISTEN_FDS");
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* IO callback for listening sockets: handle new connections. This callback
|
||||
|
@ -494,10 +532,71 @@ Conn_InitListeners( void )
|
|||
{
|
||||
/* Initialize ports on which the server should accept connections */
|
||||
unsigned int created = 0;
|
||||
char *copy, *listen_addr;
|
||||
char *af_str, *copy, *listen_addr;
|
||||
int count, fd, i, addr_len;
|
||||
ng_ipaddr_t addr;
|
||||
|
||||
assert(Conf_ListenAddress);
|
||||
|
||||
count = my_sd_listen_fds();
|
||||
if (count < 0) {
|
||||
Log(LOG_INFO,
|
||||
"Not re-initializing listening sockets of systemd(8) ...");
|
||||
return 0;
|
||||
}
|
||||
if (count > 0) {
|
||||
/* systemd(8) passed sockets to us, so don't try to initialize
|
||||
* listening sockets on our own but use the passed ones */
|
||||
LogDebug("Initializing %d systemd sockets ...", count);
|
||||
for (i = 0; i < count; i++) {
|
||||
fd = SD_LISTEN_FDS_START + i;
|
||||
addr_len = (int)sizeof(addr);
|
||||
getsockname(fd, (struct sockaddr *)&addr, (socklen_t*)&addr_len);
|
||||
#ifdef WANT_IPV6
|
||||
if (addr.sin4.sin_family != AF_INET && addr.sin4.sin_family != AF_INET6)
|
||||
#else
|
||||
if (addr.sin4.sin_family != AF_INET)
|
||||
#endif
|
||||
{
|
||||
/* Socket is of unsupported type! For example, systemd passed in
|
||||
* an IPv6 socket but ngIRCd isn't compiled with IPv6 support. */
|
||||
switch (addr.sin4.sin_family)
|
||||
{
|
||||
case AF_UNSPEC: af_str = "AF_UNSPEC"; break;
|
||||
case AF_UNIX: af_str = "AF_UNIX"; break;
|
||||
case AF_INET: af_str = "AF_INET"; break;
|
||||
#ifdef AF_INET6
|
||||
case AF_INET6: af_str = "AF_INET6"; break;
|
||||
#endif
|
||||
#ifdef AF_NETLINK
|
||||
case AF_NETLINK: af_str = "AF_NETLINK"; break;
|
||||
#endif
|
||||
default: af_str = "unknown"; break;
|
||||
}
|
||||
Log(LOG_CRIT,
|
||||
"Socket %d is of unsupported type \"%s\" (%d), have to ignore it!",
|
||||
fd, af_str, addr.sin4.sin_family);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
Init_Socket(fd);
|
||||
if (!io_event_create(fd, IO_WANTREAD, cb_listen)) {
|
||||
Log(LOG_ERR,
|
||||
"io_event_create(): Can't add fd %d: %s!",
|
||||
fd, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
Log(LOG_INFO,
|
||||
"Initialized socket %d from systemd(8): %s:%d.", fd,
|
||||
ng_ipaddr_tostr(&addr), ng_ipaddr_getport(&addr));
|
||||
created++;
|
||||
}
|
||||
return created;
|
||||
}
|
||||
|
||||
/* not using systemd socket activation, initialize listening sockets: */
|
||||
|
||||
/* can't use Conf_ListenAddress directly, see below */
|
||||
copy = strdup(Conf_ListenAddress);
|
||||
if (!copy) {
|
||||
|
@ -541,7 +640,12 @@ Conn_ExitListeners( void )
|
|||
int *fd;
|
||||
size_t arraylen;
|
||||
|
||||
/* Get number of listening sockets to shut down. There can be none
|
||||
* if ngIRCd has been "socket activated" by systemd. */
|
||||
arraylen = array_length(&My_Listeners, sizeof (int));
|
||||
if (arraylen < 1)
|
||||
return;
|
||||
|
||||
Log(LOG_INFO,
|
||||
"Shutting down all listening sockets (%d total) ...", arraylen);
|
||||
fd = array_start(&My_Listeners);
|
||||
|
@ -836,6 +940,15 @@ Conn_Handler(void)
|
|||
PACKAGE_NAME);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Should ngIRCd timeout when idle? */
|
||||
if (Conf_IdleTimeout > 0 && NumConnectionsAccepted > 0
|
||||
&& idle_t > 0 && time(NULL) - idle_t >= Conf_IdleTimeout) {
|
||||
LogDebug("Server idle timeout reached: %d second%s. Initiating shutdown ...",
|
||||
Conf_IdleTimeout,
|
||||
Conf_IdleTimeout == 1 ? "" : "s");
|
||||
NGIRCd_SignalQuit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (NGIRCd_SignalQuit)
|
||||
|
@ -1197,6 +1310,8 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie
|
|||
NumConnections--;
|
||||
LogDebug("Shutdown of connection %d completed, %ld connection%s left.",
|
||||
Idx, NumConnections, NumConnections != 1 ? "s" : "");
|
||||
|
||||
idle_t = NumConnections > 0 ? 0 : time(NULL);
|
||||
} /* Conn_Close */
|
||||
|
||||
|
||||
|
@ -1568,6 +1683,7 @@ static void
|
|||
Account_Connection(void)
|
||||
{
|
||||
NumConnections++;
|
||||
idle_t = 0;
|
||||
if (NumConnections > NumConnectionsMax)
|
||||
NumConnectionsMax = NumConnections;
|
||||
LogDebug("Total number of connections now %lu (max %lu).",
|
||||
|
|
|
@ -109,7 +109,7 @@ Log_ReInit(void)
|
|||
GLOBAL void
|
||||
Log_Exit( void )
|
||||
{
|
||||
Log(LOG_NOTICE, "%s done%s, served %lu connection%s.", PACKAGE_NAME,
|
||||
Log(LOG_INFO, "%s done%s, served %lu connection%s.", PACKAGE_NAME,
|
||||
NGIRCd_SignalRestart ? " (restarting)" : "", Conn_CountAccepted(),
|
||||
Conn_CountAccepted() == 1 ? "" : "s");
|
||||
#ifdef SYSLOG
|
||||
|
|
Loading…
Reference in New Issue