/*
* ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2009 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2010 Alexander Barton <alex@barton.de>
*
* 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
#include "imp.h"
#include <assert.h>
#ifdef PROTOTYPES
-# include <stdarg.h>
+# include <stdarg.h>
#else
-# include <varargs.h>
+# include <varargs.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#ifdef HAVE_NETINET_IP_H
+# ifdef HAVE_NETINET_IN_SYSTM_H
+# include <netinet/in_systm.h>
+# endif
# include <netinet/ip.h>
#endif
#include "array.h"
#include "defines.h"
-#include "resolve.h"
#include "exp.h"
#include "conn.h"
#include "imp.h"
#include "ngircd.h"
+#include "array.h"
#include "client.h"
#include "conf.h"
#include "conn-ssl.h"
#include "conn-zip.h"
#include "conn-func.h"
#include "log.h"
+#include "ng_ipaddr.h"
#include "parse.h"
+#include "resolve.h"
#include "tool.h"
#ifdef ZEROCONF
static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest ));
static void Simple_Message PARAMS(( int Sock, const char *Msg ));
static int NewListener PARAMS(( const char *listen_addr, UINT16 Port ));
+static void Account_Connection PARAMS((void));
+
static array My_Listeners;
static array My_ConnArray;
-static size_t NumConnections;
+static size_t NumConnections, NumConnectionsMax, NumConnectionsAccepted;
#ifdef TCPWRAP
int allow_severity = LOG_INFO;
case 0:
return; /* EAGAIN: callback will be invoked again by IO layer */
default:
- Conn_Close(idx, "Socket closed!", "SSL accept error", false);
+ Conn_Close(idx, "SSL accept error, closing socket", "SSL accept error", false);
return;
}
if (what & IO_WANTREAD)
Pool_Size = Conf_MaxConnections;
if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)Pool_Size)) {
- Log( LOG_EMERG, "Can't allocate memory! [Conn_Init]" );
- exit( 1 );
+ Log(LOG_EMERG, "Can't allocate memory! [Conn_Init]");
+ exit(1);
}
/* FIXME: My_Connetions/Pool_Size is needed by other parts of the
My_Connections = (CONNECTION*) array_start(&My_ConnArray);
LogDebug("Allocated connection pool for %d items (%ld bytes).",
- array_length(&My_ConnArray, sizeof( CONNECTION )), array_bytes(&My_ConnArray));
+ array_length(&My_ConnArray, sizeof(CONNECTION)),
+ array_bytes(&My_ConnArray));
- assert( array_length(&My_ConnArray, sizeof( CONNECTION )) >= (size_t) Pool_Size);
+ assert(array_length(&My_ConnArray, sizeof(CONNECTION)) >= (size_t)Pool_Size);
array_free( &My_Listeners );
- /* Connection-Struktur initialisieren */
- for( i = 0; i < Pool_Size; i++ ) Init_Conn_Struct( i );
-
- /* Global write counter */
- WCounter = 0;
+ for (i = 0; i < Pool_Size; i++)
+ Init_Conn_Struct(i);
} /* Conn_Init */
} /* 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))
{
if (SSL_WantWrite(&My_Connections[i]))
continue; /* TLS/SSL layer needs to write data; deal with this first */
#endif
- if (Resolve_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);
}
*/
#ifdef PROTOTYPES
GLOBAL bool
-Conn_WriteStr( CONN_ID Idx, char *Format, ... )
+Conn_WriteStr(CONN_ID Idx, const char *Format, ...)
#else
GLOBAL bool
-Conn_WriteStr( Idx, Format, va_alist )
+Conn_WriteStr(Idx, Format, va_alist)
CONN_ID Idx;
-char *Format;
+const char *Format;
va_dcl
#endif
{
in_k, out_k);
}
- /* cancel running resolver */
- if (Resolve_INPROGRESS(&My_Connections[Idx].res_stat))
- Resolve_Shutdown(&My_Connections[Idx].res_stat);
-
/* Servers: Modify time of next connect attempt? */
Conf_UnsetServer( Idx );
} /* Conn_Close */
+GLOBAL long
+Conn_Count(void)
+{
+ return NumConnections;
+} /* Conn_Count */
+
+
+GLOBAL long
+Conn_CountMax(void)
+{
+ return NumConnectionsMax;
+} /* Conn_CountMax */
+
+
+GLOBAL long
+Conn_CountAccepted(void)
+{
+ return NumConnectionsAccepted;
+} /* Conn_CountAccepted */
+
+
GLOBAL void
Conn_SyncServerStruct( void )
{
Log(LOG_CRIT, "Can't accept connection: %s!", strerror(errno));
return -1;
}
+ NumConnectionsAccepted++;
if (!ng_ipaddr_tostr_r(&new_addr, ip_str)) {
Log(LOG_CRIT, "fd %d: Can't convert IP address!", new_sock);
identsock = -1;
#endif
if (!Conf_NoDNS)
- Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr,
+ 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);
-
- NumConnections++;
- LogDebug("Total number of connections now %ld.", NumConnections);
+ Account_Connection();
return new_sock;
} /* New_Connection */
+static void
+Account_Connection(void)
+{
+ NumConnections++;
+ if (NumConnections > NumConnectionsMax)
+ NumConnectionsMax = NumConnections;
+ LogDebug("Total number of connections now %lu (max %lu).",
+ NumConnections, NumConnectionsMax);
+} /* Account_Connection */
+
+
static CONN_ID
Socket2Index( int Sock )
{
/* Okay, try to connect now */
Conf_Server[i].lasttry = time_now;
Conf_Server[i].conn_id = SERVER_WAIT;
- assert(Resolve_Getfd(&Conf_Server[i].res_stat) < 0);
+ assert(Proc_GetPipeFd(&Conf_Server[i].res_stat) < 0);
Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, cb_Connect_to_Server);
}
} /* Check_Servers */
}
/* Conn_Close() decrements this counter again */
- NumConnections++;
+ Account_Connection();
Client_SetIntroducer( c, c );
Client_SetToken( c, TOKEN_OUTBOUND );
My_Connections[Idx].signon = now;
My_Connections[Idx].lastdata = now;
My_Connections[Idx].lastprivmsg = now;
- Resolve_Init(&My_Connections[Idx].res_stat);
+ Proc_InitStruct(&My_Connections[Idx].proc_stat);
} /* Init_Conn_Struct */
LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events);
for (i=0; i < MAX_SERVERS; i++) {
- if (Resolve_Getfd(&Conf_Server[i].res_stat) == fd )
+ if (Proc_GetPipeFd(&Conf_Server[i].res_stat) == fd )
break;
}
}
/* Read result from pipe */
- len = Resolve_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs));
+ len = Proc_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs));
if (len == 0)
return;
* 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 )
- && ( Resolve_Getfd(&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