/*
* 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
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
+ * use the one provided by systemd itself, because the sockets will be
* used in a forked child process with a new PID, and this would trigger
* an error in the standard implementation.
*
my_sd_listen_fds(void)
{
const char *e;
- long count;
+ int count;
/* Check if LISTEN_PID exists; but we ignore the result, because
* normally ngircd forks a child before checking this, and therefore
e = getenv("LISTEN_FDS");
if (!e || !*e)
return -1;
- count = atol(e);
+ count = atoi(e);
unsetenv("LISTEN_FDS");
return count;
if (server < 0) {
Log(LOG_ERR, "Connection on socket %d to \"%s\" aborted!",
sock, My_Connections[idx].host);
- Conn_Close(idx, "Connection aborted!", NULL, false);
+ Conn_Close(idx, "Connection aborted", NULL, false);
return;
}
#ifdef SSL_SUPPORT
/**
- * IO callback for established SSL-enabled client and server connections.
+ * IO callback for new SSL-enabled client and server connections.
*
* @param sock Socket descriptor.
* @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...).
*/
static void
-cb_clientserver_ssl(int sock, short what)
+cb_clientserver_ssl(int sock, UNUSED short what)
{
CONN_ID idx = Socket2Index(sock);
case 0:
return; /* EAGAIN: callback will be invoked again by IO layer */
default:
- Conn_Close(idx, "SSL accept error, closing socket", "SSL accept error", false);
+ Conn_Close(idx,
+ "SSL accept error, closing socket", "SSL accept error",
+ false);
return;
}
- if (what & IO_WANTREAD)
- Read_Request(idx);
-
- if (what & IO_WANTWRITE)
- Handle_Write(idx);
io_event_setcb(sock, cb_clientserver); /* SSL handshake completed */
}
/**
- * Initialize connecion module.
+ * Initialize connection module.
*/
GLOBAL void
Conn_Init( void )
{
CONN_ID i;
- /* Speicher fuer Verbindungs-Pool anfordern */
Pool_Size = CONNECTION_POOL;
if ((Conf_MaxConnections > 0) &&
(Pool_Size > Conf_MaxConnections))
{
/* Initialize ports on which the server should accept connections */
unsigned int created = 0;
- char *copy, *listen_addr;
- int count, fd, i;
+ char *af_str, *copy, *listen_addr;
+ int count, fd, i, addr_len;
+ ng_ipaddr_t addr;
assert(Conf_ListenAddress);
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,
continue;
}
Log(LOG_INFO,
- "Initialized socket %d from systemd.", fd);
+ "Initialized socket %d from systemd(8): %s:%d.", fd,
+ ng_ipaddr_tostr(&addr), ng_ipaddr_getport(&addr));
created++;
}
return created;
/* Look for non-empty read buffers ... */
for (i = 0; i < Pool_Size; i++) {
if ((My_Connections[i].sock > NONE)
- && (array_bytes(&My_Connections[i].rbuf) > 0)
- && (My_Connections[i].delaytime <= t)) {
+ && (array_bytes(&My_Connections[i].rbuf) > 0)) {
/* ... and try to handle the received data */
bytes_processed = Handle_Buffer(i);
/* if we processed data, and there might be
* which is the granularity with witch we handle "penalty
* times" for example.
* Note: tv_sec/usec are undefined(!) after io_dispatch()
- * returns, so we have to set it beforce each call to it! */
+ * returns, so we have to set it before each call to it! */
tv.tv_usec = 0;
tv.tv_sec = 1;
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)
*
* So we have a big problem here: we should send more bytes
* to the network than we are allowed to and we don't know
- * the originator (any more). The "old" behaviour of blaming
+ * the originator (any more). The "old" behavior of blaming
* the receiver ("next hop") is a bad idea (it could be just
* an other server only routing the message!), so the only
* option left is to shorten the string and to hope that the
/* Is this link already shutting down? */
if( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ISCLOSING )) {
/* Conn_Close() has been called recursively for this link;
- * probabe reason: Handle_Write() failed -- see below. */
- LogDebug("Recursive request to close connection: %d", Idx );
+ * probable reason: Handle_Write() failed -- see below. */
+ LogDebug("Recursive request to close connection %d!", Idx );
return;
}
c = Conn_GetClient( Idx );
#ifdef SSL_SUPPORT
if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_SSL )) {
- Log(LOG_INFO, "SSL connection %d shutting down ...", Idx);
+ LogDebug("SSL connection %d shutting down ...", Idx);
ConnSSL_Free(&My_Connections[Idx]);
}
#endif
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 */
if (errno == EAGAIN || errno == EINTR)
return true;
- Log(LOG_ERR, "Write error on connection %d (socket %d): %s!",
- Idx, My_Connections[Idx].sock, strerror(errno));
- Conn_Close(Idx, "Write error!", NULL, false);
+ if (!Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ISCLOSING))
+ Log(LOG_ERR,
+ "Write error on connection %d (socket %d): %s!",
+ Idx, My_Connections[Idx].sock, strerror(errno));
+ else
+ LogDebug("Recursive write error on connection %d (socket %d): %s!",
+ Idx, My_Connections[Idx].sock, strerror(errno));
+ Conn_Close(Idx, "Write error", NULL, false);
return false;
}
Account_Connection(void)
{
NumConnections++;
+ idle_t = 0;
if (NumConnections > NumConnectionsMax)
NumConnectionsMax = NumConnections;
LogDebug("Total number of connections now %lu (max %lu).",
/**
- * Read data from the network to the read buffer. If an error occures,
+ * Read data from the network to the read buffer. If an error occurs,
* the socket of this connection will be shut down.
*
* @param Idx Connection index.
maxcmd = (int)(Client_UserCount() / 5)
+ MAX_COMMANDS_SERVER_MIN;
/* Allow servers to handle even more commands while peering
- * to speed up server login and network synchronisation. */
+ * to speed up server login and network synchronization. */
if (Conn_LastPing(Idx) == 0)
maxcmd *= 5;
break;
/**
* Read results of a resolver sub-process from the pipe and update the
- * apropriate connection/client structure(s): hostname and/or IDENT user name.
+ * appropriate connection/client structure(s): hostname and/or IDENT user name.
*
* @param r_fd File descriptor of the pipe to the sub-process.
* @param events (ignored IO specification)
Class_HandleServerBans(c);
}
#ifdef DEBUG
- else Log( LOG_DEBUG, "Resolver: discarding result for already registered connection %d.", i );
+ else
+ LogDebug("Resolver: discarding result for already registered connection %d.", i);
#endif
} /* cb_Read_Resolver_Result */
#ifdef SSL_SUPPORT
/**
- * Get information about used SSL chiper.
+ * Get information about used SSL cipher.
*
* @param Idx Connection index number.
* @param buf Buffer for returned information text.
return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL);
}
+
+GLOBAL char *
+Conn_GetCertFp(CONN_ID Idx)
+{
+ if (Idx < 0)
+ return NULL;
+ assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
+ return ConnSSL_GetCertFp(&My_Connections[Idx]);
+}
+
+
+GLOBAL bool
+Conn_SetCertFp(CONN_ID Idx, const char *fingerprint)
+{
+ if (Idx < 0)
+ return false;
+ assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
+ return ConnSSL_SetCertFp(&My_Connections[Idx], fingerprint);
+}
+#else
+GLOBAL bool
+Conn_UsesSSL(UNUSED CONN_ID Idx)
+{
+ return false;
+}
+
+
+GLOBAL char *
+Conn_GetCertFp(UNUSED CONN_ID Idx)
+{
+ return NULL;
+}
+
+
+GLOBAL bool
+Conn_SetCertFp(UNUSED CONN_ID Idx, UNUSED const char *fingerprint)
+{
+ return true;
+}
#endif