+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));
+
+static void
+cb_listen(int sock, short irrelevant)
+{
+ (void) irrelevant;
+ if (New_Connection( sock ) >= 0)
+ NumConnections++;
+ LogDebug("Total number of connections now %ld.", NumConnections);
+}
+
+
+#ifdef SSL_SUPPORT
+static void
+cb_listen_ssl(int sock, short irrelevant)
+{
+ int fd;
+ (void) irrelevant;
+ fd = New_Connection(sock);
+ if (fd < 0)
+ return;
+
+ NumConnections++;
+ LogDebug("Total number of connections now %ld.", NumConnections);
+ io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl);
+}
+#endif
+
+
+static void
+cb_connserver(int sock, UNUSED short what)
+{
+ int res, err;
+ 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);
+
+ /* 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[Conf_GetServer(idx)].port,
+ idx, strerror(err));
+
+ res = Conf_GetServer(idx);
+ assert(res >= 0);
+
+ Conn_Close(idx, "Can't connect!", NULL, false);
+
+ if (res < 0)
+ return;
+ if (ng_ipaddr_af(&Conf_Server[res].dst_addr[0])) {
+ /* more addresses to try... */
+ New_Server(res, &Conf_Server[res].dst_addr[0]);
+ /* connection to dst_addr[0] in progress, remove this address... */
+ Conf_Server[res].dst_addr[0] = Conf_Server[res].dst_addr[1];
+
+ memset(&Conf_Server[res].dst_addr[1], 0, sizeof(&Conf_Server[res].dst_addr[1]));
+ }
+ return;
+ }
+
+ res = Conf_GetServer(idx);
+ assert(res >= 0);
+ if (res >= 0) /* connect succeeded, remove all additional addresses */
+ memset(&Conf_Server[res].dst_addr, 0, sizeof(&Conf_Server[res].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);
+}
+
+
+static void
+server_login(CONN_ID idx)
+{
+ Log( LOG_INFO, "Connection %d with \"%s:%d\" established. Now logging in ...", idx,
+ 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
+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
+
+
+static void
+cb_clientserver(int sock, short what)
+{
+ CONN_ID idx = Socket2Index(sock);
+
+ assert(idx >= 0);
+
+ if (idx < 0) {
+ io_close(sock);
+ return;
+ }
+#ifdef SSL_SUPPORT
+ if (what & IO_WANTREAD || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE)))
+ Read_Request( idx ); /* if TLS layer needs to write additional data, call Read_Request instead so SSL/TLS can continue */
+#else
+ if (what & IO_WANTREAD)
+ Read_Request( idx );
+#endif
+ if (what & IO_WANTWRITE)
+ Handle_Write( idx );
+}
+
+
+#ifdef SSL_SUPPORT
+static void
+cb_clientserver_ssl(int sock, short what)
+{
+ CONN_ID idx = Socket2Index(sock);
+
+ assert(idx >= 0);
+
+ if (idx < 0) {
+ io_close(sock);
+ return;
+ }
+
+ switch (ConnSSL_Accept(&My_Connections[idx])) {
+ case 1: break; /* OK */
+ case 0: return; /* EAGAIN: this callback will be invoked again by the io layer */
+ default:
+ Conn_Close( idx, "Socket closed!", "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 */
+}
+#endif
+