#include "log.h"
#include "ng_ipaddr.h"
#include "parse.h"
-#include "proc.h"
#include "resolve.h"
#include "tool.h"
#define MAX_COMMANDS 3
#define MAX_COMMANDS_SERVER 10
+#define MAX_COMMANDS_SERVICE MAX_COMMANDS_SERVER
static bool Handle_Write PARAMS(( CONN_ID Idx ));
if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) {
/* more addresses to try... */
- New_Server(res, &Conf_Server[server].dst_addr[0]);
+ New_Server(server, &Conf_Server[server].dst_addr[0]);
/* connection to dst_addr[0] is now in progress, so
* remove this address... */
Conf_Server[server].dst_addr[0] =
} /* Conn_Exit */
+/**
+ * Close all sockets (file descriptors) of open connections.
+ * This is useful in forked child processes, for example, to make sure that
+ * they don't hold connections open that the main process wants to close.
+ */
+GLOBAL void
+Conn_CloseAllSockets(void)
+{
+ CONN_ID idx;
+
+ for(idx = 0; idx < Pool_Size; idx++) {
+ if(My_Connections[idx].sock > NONE)
+ close(My_Connections[idx].sock);
+ }
+}
+
+
static unsigned int
ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short))
{
unsigned int created = 0;
char *copy, *listen_addr;
- if (!io_library_init(CONNECTION_POOL)) {
- Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno));
- return -1;
- }
-
assert(Conf_ListenAddress);
/* can't use Conf_ListenAddress directly, see below */
}
#else
static inline bool
-SSL_WantRead(UNUSED const CONNECTION *c) { return false; }
+SSL_WantRead(UNUSED const CONNECTION *c)
+{ return false; }
static inline bool
-SSL_WantWrite(UNUSED const CONNECTION *c) { return false; }
+SSL_WantWrite(UNUSED const CONNECTION *c)
+{ return false; }
#endif
Rendezvous_Handler();
#endif
- /* Should the configuration be reloaded? */
- if (NGIRCd_SignalRehash)
- NGIRCd_Rehash();
-
/* Check configured servers and established links */
Check_Servers();
Check_Connections();
if (SSL_WantWrite(&My_Connections[i]))
continue; /* TLS/SSL layer needs to write data; deal with this first */
#endif
- if (Proc_InProgress(&My_Connections[i].res_stat)) {
- /* Wait for completion of resolver sub-process ... */
+ if (Proc_InProgress(&My_Connections[i].proc_stat)) {
+ /* Wait for completion of forked subprocess
+ * and ignore the socket in the meantime ... */
io_event_del(My_Connections[i].sock,
IO_WANTREAD);
continue;
IO_WANTREAD);
continue;
}
+
io_event_add(My_Connections[i].sock, IO_WANTREAD);
}
in_k, out_k);
}
- /* cancel running resolver */
- if (Proc_InProgress(&My_Connections[Idx].res_stat))
- Proc_Kill(&My_Connections[Idx].res_stat);
-
/* Servers: Modify time of next connect attempt? */
Conf_UnsetServer( Idx );
} /* Conn_CountAccepted */
+/**
+ * Synchronize established connections and configured server structures
+ * after a configuration update and store the correct connection IDs, if any.
+ */
GLOBAL void
-Conn_SyncServerStruct( void )
+Conn_SyncServerStruct(void)
{
- /* Synchronize server structures (connection IDs):
- * connections <-> configuration */
-
CLIENT *client;
CONN_ID i;
int c;
- for( i = 0; i < Pool_Size; i++ ) {
- /* Established connection? */
- if (My_Connections[i].sock < 0)
+ for (i = 0; i < Pool_Size; i++) {
+ if (My_Connections[i].sock == NONE)
continue;
- /* Server connection? */
- client = Conn_GetClient( i );
- if(( ! client ) || ( Client_Type( client ) != CLIENT_SERVER )) continue;
+ /* Server link? */
+ client = Conn_GetClient(i);
+ if (!client || Client_Type(client) != CLIENT_SERVER)
+ continue;
- for( c = 0; c < MAX_SERVERS; c++ )
- {
+ for (c = 0; c < MAX_SERVERS; c++) {
/* Configured server? */
- if( ! Conf_Server[c].host[0] ) continue;
+ if (!Conf_Server[c].host[0])
+ continue;
- /* Duplicate? */
- if( strcmp( Conf_Server[c].name, Client_ID( client )) == 0 )
+ if (strcasecmp(Conf_Server[c].name, Client_ID(client)) == 0)
Conf_Server[c].conn_id = i;
}
}
identsock = new_sock;
#ifdef IDENTAUTH
- if (Conf_NoIdent)
+ if (!Conf_Ident)
identsock = -1;
#endif
- if (!Conf_NoDNS)
- Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr,
+ if (Conf_DNS)
+ Resolve_Addr(&My_Connections[new_sock].proc_stat, &new_addr,
identsock, cb_Read_Resolver_Result);
- /* ngIRCd waits up to 4 seconds for the result of the asynchronous
- * DNS and IDENT resolver subprocess using the "penalty" mechanism.
- * If there are results earlier, the delay is aborted. */
- Conn_SetPenalty(new_sock, 4);
-
Account_Connection();
return new_sock;
} /* New_Connection */
* registered as a user, server or service connection. Don't update
* otherwise, so users have at least Conf_PongTimeout seconds time to
* register with the IRC server -- see Check_Connections().
- * Set "lastping", too, so we can handle time shifts backwards ... */
+ * Update "lastping", too, if time shifted backwards ... */
c = Conn_GetClient(Idx);
if (c && (Client_Type(c) == CLIENT_USER
|| Client_Type(c) == CLIENT_SERVER
My_Connections[Idx].bps = 0;
My_Connections[Idx].lastdata = t;
- My_Connections[Idx].lastping = My_Connections[Idx].lastdata;
+ if (My_Connections[Idx].lastping > t)
+ My_Connections[Idx].lastping = t;
}
/* Look at the data in the (read-) buffer of this connection */
My_Connections[Idx].bps += Handle_Buffer(Idx);
if (Client_Type(c) != CLIENT_SERVER
+ && Client_Type(c) != CLIENT_UNKNOWNSERVER
+ && Client_Type(c) != CLIENT_SERVICE
&& My_Connections[Idx].bps >= maxbps) {
LogDebug("Throttling connection %d: BPS exceeded! (%u >= %u)",
Idx, My_Connections[Idx].bps, maxbps);
/**
* Handle all data in the connection read-buffer.
* Data is processed until no complete command is left in the read buffer,
- * or MAX_COMMANDS[_SERVER] commands were processed.
+ * or MAX_COMMANDS[_SERVER|_SERVICE] commands were processed.
* When a fatal error occurs, the connection is shut down.
* @param Idx Index of the connection.
* @return number of bytes processed.
/* Servers do get special command limits, so they can process
* all the messages that are required while peering. */
- if (Client_Type(c) == CLIENT_SERVER)
- maxcmd = MAX_COMMANDS_SERVER;
+ switch (Client_Type(c)) {
+ case CLIENT_SERVER:
+ maxcmd = MAX_COMMANDS_SERVER; break;
+ case CLIENT_SERVICE:
+ maxcmd = MAX_COMMANDS_SERVICE; break;
+ }
starttime = time(NULL);
for (i=0; i < maxcmd; i++) {
} /* Handle_Buffer */
+/**
+ * Check whether established connections are still alive or not.
+ * If not, play PING-PONG first; and if that doesn't help either,
+ * disconnect the respective peer.
+ */
static void
Check_Connections(void)
{
- /* check if connections are alive. if not, play PING-PONG first.
- * if this doesn't help either, disconnect client. */
CLIENT *c;
CONN_ID i;
char msg[64];
} /* Check_Connections */
+/**
+ * Check if further server links should be established.
+ */
static void
-Check_Servers( void )
+Check_Servers(void)
{
- /* Check if we can establish further server links */
-
int i, n;
time_t time_now;
+ time_now = time(NULL);
+
/* Check all configured servers */
- for( i = 0; i < MAX_SERVERS; i++ ) {
- /* Valid outgoing server which isn't already connected or disabled? */
- if(( ! Conf_Server[i].host[0] ) || ( ! Conf_Server[i].port > 0 ) ||
- ( Conf_Server[i].conn_id > NONE ) || ( Conf_Server[i].flags & CONF_SFLAG_DISABLED ))
- continue;
+ for (i = 0; i < MAX_SERVERS; i++) {
+ if (Conf_Server[i].conn_id != NONE)
+ continue; /* Already establishing or connected */
+ if (!Conf_Server[i].host[0] || !Conf_Server[i].port > 0)
+ continue; /* No host and/or port configured */
+ if (Conf_Server[i].flags & CONF_SFLAG_DISABLED)
+ continue; /* Disabled configuration entry */
+ if (Conf_Server[i].lasttry > (time_now - Conf_ConnectRetry))
+ continue; /* We have to wait a little bit ... */
/* Is there already a connection in this group? */
- if( Conf_Server[i].group > NONE ) {
+ if (Conf_Server[i].group > NONE) {
for (n = 0; n < MAX_SERVERS; n++) {
- if (n == i) continue;
+ if (n == i)
+ continue;
if ((Conf_Server[n].conn_id != NONE) &&
- (Conf_Server[n].group == Conf_Server[i].group))
- break;
+ (Conf_Server[n].group == Conf_Server[i].group))
+ break;
}
- if (n < MAX_SERVERS) continue;
+ if (n < MAX_SERVERS)
+ continue;
}
- /* Check last connect attempt? */
- time_now = time(NULL);
- if( Conf_Server[i].lasttry > (time_now - Conf_ConnectRetry))
- continue;
-
/* Okay, try to connect now */
+ Log(LOG_NOTICE,
+ "Preparing to establish a new server link for \"%s\" ...",
+ Conf_Server[i].name);
Conf_Server[i].lasttry = time_now;
Conf_Server[i].conn_id = SERVER_WAIT;
assert(Proc_GetPipeFd(&Conf_Server[i].res_stat) < 0);
- Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, cb_Connect_to_Server);
+ Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host,
+ cb_Connect_to_Server);
}
} /* Check_Servers */
return;
}
- Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ",
- Conf_Server[Server].host, ip_str, Conf_Server[Server].port );
+ Log(LOG_INFO, "Establishing connection for \"%s\" to \"%s\" (%s) port %d ... ",
+ Conf_Server[Server].name, Conf_Server[Server].host, ip_str,
+ Conf_Server[Server].port);
af_dest = ng_ipaddr_af(dest);
new_sock = socket(af_dest, SOCK_STREAM, 0);
My_Connections[Idx].signon = now;
My_Connections[Idx].lastdata = now;
My_Connections[Idx].lastprivmsg = now;
- Proc_InitStruct(&My_Connections[Idx].res_stat);
+ Proc_InitStruct(&My_Connections[Idx].proc_stat);
} /* Init_Conn_Struct */
LogDebug("Setting IP_TOS on socket %d to IPTOS_LOWDELAY.", Sock);
if (setsockopt(Sock, IPPROTO_IP, IP_TOS, &value,
(socklen_t) sizeof(value))) {
- Log(LOG_ERR, "Can't set socket option IP_TOS: %s!",
- strerror(errno));
+ LogDebug("Can't set socket option IP_TOS: %s!",
+ strerror(errno));
/* ignore this error */
}
#endif
}
/* Read result from pipe */
- len = Resolve_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs));
- if (len == 0)
+ len = Proc_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs));
+ if (len == 0) {
+ /* Error resolving hostname: reset server structure */
+ Conf_Server[i].conn_id = NONE;
return;
+ }
assert((len % sizeof(ng_ipaddr_t)) == 0);
* IDENT user name.*/
CLIENT *c;
- int i;
+ CONN_ID i;
size_t len;
char *identptr;
#ifdef IDENTAUTH
#endif
LogDebug("Resolver: Got callback on fd %d, events %d", r_fd, events );
-
- /* Search associated connection ... */
- for( i = 0; i < Pool_Size; i++ ) {
- if(( My_Connections[i].sock != NONE )
- && (Proc_GetPipeFd(&My_Connections[i].res_stat) == r_fd))
- break;
- }
- if( i >= Pool_Size ) {
+ i = Conn_GetFromProc(r_fd);
+ if (i == NONE) {
/* Ops, none found? Probably the connection has already
* been closed!? We'll ignore that ... */
io_close( r_fd );
}
/* Read result from pipe */
- len = Resolve_Read(&My_Connections[i].res_stat, readbuf, sizeof readbuf -1);
+ len = Proc_Read(&My_Connections[i].proc_stat, readbuf, sizeof readbuf -1);
if (len == 0)
return;
#ifdef DEBUG
else Log( LOG_DEBUG, "Resolver: discarding result for already registered connection %d.", i );
#endif
- /* Reset penalty time */
- Conn_ResetPenalty( i );
} /* cb_Read_Resolver_Result */
return c ? c->client : NULL;
}
+/**
+ * Get PROC_STAT sub-process structure of a connection.
+ * @param Idx Connection index number
+ * @return PROC_STAT structure
+ */
+GLOBAL PROC_STAT *
+Conn_GetProcStat(CONN_ID Idx)
+{
+ CONNECTION *c;
+
+ assert(Idx >= 0);
+ c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx);
+ assert(c != NULL);
+ return &c->proc_stat;
+} /* Conn_GetProcStat */
+
+
+/**
+ * Get CONN_ID from file descriptor associated to a subprocess structure.
+ * @param fd File descriptor
+ * @return CONN_ID or NONE (-1)
+ */
+GLOBAL CONN_ID
+Conn_GetFromProc(int fd)
+{
+ int i;
+
+ assert(fd > 0);
+ for (i = 0; i < Pool_Size; i++) {
+ if ((My_Connections[i].sock != NONE)
+ && (Proc_GetPipeFd(&My_Connections[i].proc_stat) == fd))
+ return i;
+ }
+ return NONE;
+} /* Conn_GetFromProc */
+
#ifdef SSL_SUPPORT
#endif
+#ifdef DEBUG
+
+GLOBAL void
+Conn_DebugDump(void)
+{
+ int i;
+
+ Log(LOG_DEBUG, "Connection status:");
+ for (i = 0; i < Pool_Size; i++) {
+ if (My_Connections[i].sock == NONE)
+ continue;
+ Log(LOG_DEBUG,
+ " - %d: host=%s, lastdata=%ld, lastping=%ld, delaytime=%ld, flag=%d, options=%d, bps=%d, client=%s",
+ My_Connections[i].sock, My_Connections[i].host,
+ My_Connections[i].lastdata, My_Connections[i].lastping,
+ My_Connections[i].delaytime, My_Connections[i].flag,
+ My_Connections[i].options, My_Connections[i].bps,
+ My_Connections[i].client ? Client_ID(My_Connections[i].client) : "-");
+ }
+} /* Conn_DumpClients */
+
+#endif
+
+
/* -eof- */