+#define MAX_COMMANDS 3
+#define MAX_COMMANDS_SERVER_MIN 10
+#define MAX_COMMANDS_SERVICE 10
+
+
+static bool Handle_Write PARAMS(( CONN_ID Idx ));
+static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
+static int New_Connection PARAMS(( int Sock ));
+static CONN_ID Socket2Index PARAMS(( int Sock ));
+static void Read_Request PARAMS(( CONN_ID Idx ));
+static unsigned int Handle_Buffer PARAMS(( CONN_ID Idx ));
+static void Check_Connections PARAMS(( void ));
+static void Check_Servers PARAMS(( void ));
+static void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
+static bool Init_Socket PARAMS(( int Sock ));
+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, NumConnectionsMax, NumConnectionsAccepted;
+
+#ifdef TCPWRAP
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_ERR;
+#endif
+
+static void server_login PARAMS((CONN_ID idx));
+
+#ifdef SSL_SUPPORT
+extern struct SSLOptions Conf_SSLOptions;
+static void cb_connserver_login_ssl PARAMS((int sock, short what));
+static void cb_clientserver_ssl PARAMS((int sock, short what));
+#endif
+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));
+
+
+/**
+ * IO callback for listening sockets: handle new connections. This callback
+ * gets called when a new non-SSL connection should be accepted.
+ *
+ * @param sock Socket descriptor.
+ * @param irrelevant (ignored IO specification)
+ */
+static void
+cb_listen(int sock, short irrelevant)
+{
+ (void) irrelevant;
+ (void) New_Connection(sock);
+}
+
+
+#ifdef SSL_SUPPORT
+/**
+ * IO callback for listening SSL sockets: handle new connections. This callback
+ * gets called when a new SSL-enabled connection should be accepted.
+ *
+ * @param sock Socket descriptor.
+ * @param irrelevant (ignored IO specification)
+ */
+static void
+cb_listen_ssl(int sock, short irrelevant)
+{
+ int fd;
+
+ (void) irrelevant;
+ fd = New_Connection(sock);
+ if (fd < 0)
+ return;
+ io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl);
+}
+#endif
+
+
+/**
+ * IO callback for new outgoing non-SSL server connections.
+ *
+ * @param sock Socket descriptor.
+ * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...).
+ */
+static void
+cb_connserver(int sock, UNUSED short what)
+{
+ int res, err, server;
+ socklen_t sock_len;
+ CONN_ID idx = Socket2Index( sock );
+
+ if (idx <= NONE) {
+ LogDebug("cb_connserver wants to write on unknown socket?!");
+ io_close(sock);
+ return;
+ }
+
+ assert(what & IO_WANTWRITE);
+
+ /* Make sure that the server is still configured; it could have been
+ * removed in the meantime! */
+ server = Conf_GetServer(idx);
+ 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);
+ return;
+ }
+
+ /* connect() finished, get result. */
+ sock_len = (socklen_t)sizeof(err);
+ res = getsockopt(My_Connections[idx].sock, SOL_SOCKET, SO_ERROR,
+ &err, &sock_len );
+ assert(sock_len == sizeof(err));
+
+ /* Error while connecting? */
+ if ((res != 0) || (err != 0)) {
+ if (res != 0)
+ Log(LOG_CRIT, "getsockopt (connection %d): %s!",
+ idx, strerror(errno));
+ else
+ Log(LOG_CRIT,
+ "Can't connect socket to \"%s:%d\" (connection %d): %s!",
+ My_Connections[idx].host, Conf_Server[server].port,
+ idx, strerror(err));
+
+ Conn_Close(idx, "Can't connect!", NULL, false);
+
+ if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) {
+ /* more addresses to try... */
+ 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] =
+ Conf_Server[server].dst_addr[1];
+ memset(&Conf_Server[server].dst_addr[1], 0,
+ sizeof(Conf_Server[server].dst_addr[1]));
+ }
+ return;
+ }
+
+ /* connect() succeeded, remove all additional addresses */
+ memset(&Conf_Server[server].dst_addr, 0,
+ sizeof(Conf_Server[server].dst_addr));
+
+ Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING );
+#ifdef SSL_SUPPORT
+ if ( Conn_OPTION_ISSET( &My_Connections[idx], CONN_SSL_CONNECT )) {
+ io_event_setcb( sock, cb_connserver_login_ssl );
+ io_event_add( sock, IO_WANTWRITE|IO_WANTREAD );
+ return;
+ }
+#endif
+ server_login(idx);
+}
+
+
+/**
+ * Login to a remote server.
+ *
+ * @param idx Connection index.
+ */
+static void
+server_login(CONN_ID idx)
+{
+ Log(LOG_INFO,
+ "Connection %d (socket %d) with \"%s:%d\" established. Now logging in ...",
+ idx, My_Connections[idx].sock, My_Connections[idx].host,
+ Conf_Server[Conf_GetServer(idx)].port);
+
+ io_event_setcb( My_Connections[idx].sock, cb_clientserver);
+ io_event_add( My_Connections[idx].sock, IO_WANTREAD|IO_WANTWRITE);
+
+ /* Send PASS and SERVER command to peer */
+ Conn_WriteStr( idx, "PASS %s %s", Conf_Server[Conf_GetServer( idx )].pwd_out, NGIRCd_ProtoID );
+ Conn_WriteStr( idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo );
+}
+
+
+#ifdef SSL_SUPPORT
+/**
+ * IO callback for new outgoing SSL-enabled server connections.
+ *
+ * @param sock Socket descriptor.
+ * @param unused (ignored IO specification)
+ */
+static void
+cb_connserver_login_ssl(int sock, short unused)
+{
+ CONN_ID idx = Socket2Index(sock);
+
+ assert(idx >= 0);
+ if (idx < 0) {
+ io_close(sock);
+ return;
+ }
+ (void) unused;
+ switch (ConnSSL_Connect( &My_Connections[idx])) {
+ case 1: break;
+ case 0: LogDebug("ConnSSL_Connect: not ready");
+ return;
+ case -1:
+ Log(LOG_ERR, "SSL connection on socket %d failed!", sock);
+ Conn_Close(idx, "Can't connect!", NULL, false);
+ return;
+ }
+
+ Log( LOG_INFO, "SSL connection %d with \"%s:%d\" established.", idx,
+ My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port );
+
+ server_login(idx);
+}
+#endif