+ len = write(My_Connections[Idx].sock,
+ array_start(&My_Connections[Idx].wbuf), wdatalen );
+ }
+ if( len < 0 ) {
+ 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);
+ return false;
+ }
+
+ /* move any data not yet written to beginning */
+ array_moveleft(&My_Connections[Idx].wbuf, 1, (size_t)len);
+
+ return true;
+} /* Handle_Write */
+
+
+/**
+ * Count established connections to a specific IP address.
+ *
+ * @returns Number of established connections.
+ */
+static int
+Count_Connections(ng_ipaddr_t *a)
+{
+ int i, cnt;
+
+ cnt = 0;
+ for (i = 0; i < Pool_Size; i++) {
+ if (My_Connections[i].sock <= NONE)
+ continue;
+ if (ng_ipaddr_ipequal(&My_Connections[i].addr, a))
+ cnt++;
+ }
+ return cnt;
+} /* Count_Connections */
+
+
+/**
+ * Initialize new client connection on a listening socket.
+ *
+ * @param Sock Listening socket descriptor.
+ * @param IsSSL true if this socket expects SSL-encrypted data.
+ * @returns Accepted socket descriptor or -1 on error.
+ */
+static int
+New_Connection(int Sock, UNUSED bool IsSSL)
+{
+#ifdef TCPWRAP
+ struct request_info req;
+#endif
+ ng_ipaddr_t new_addr;
+ char ip_str[NG_INET_ADDRSTRLEN];
+ int new_sock, new_sock_len;
+ CLIENT *c;
+ long cnt;
+
+ assert(Sock > NONE);
+
+ LogDebug("Accepting new connection on socket %d ...", Sock);
+
+ new_sock_len = (int)sizeof(new_addr);
+ new_sock = accept(Sock, (struct sockaddr *)&new_addr,
+ (socklen_t *)&new_sock_len);
+ if (new_sock < 0) {
+ 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);
+ Simple_Message(new_sock, "ERROR :Internal Server Error");
+ close(new_sock);
+ return -1;
+ }
+
+#ifdef TCPWRAP
+ /* Validate socket using TCP Wrappers */
+ request_init(&req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock,
+ RQ_CLIENT_SIN, &new_addr, NULL);
+ fromhost(&req);
+ if (!hosts_access(&req)) {
+ Log(deny_severity,
+ "Refused connection from %s (by TCP Wrappers)!", ip_str);
+ Simple_Message(new_sock, "ERROR :Connection refused");
+ close(new_sock);
+ return -1;
+ }
+#endif
+
+ if (!Init_Socket(new_sock))
+ return -1;
+
+ /* Check global connection limit */
+ if ((Conf_MaxConnections > 0) &&
+ (NumConnections >= (size_t) Conf_MaxConnections)) {
+ Log(LOG_ALERT, "Can't accept connection: limit (%d) reached!",
+ Conf_MaxConnections);
+ Simple_Message(new_sock, "ERROR :Connection limit reached");
+ close(new_sock);
+ return -1;
+ }
+
+ /* Check IP-based connection limit */
+ cnt = Count_Connections(&new_addr);
+ if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) {
+ /* Access denied, too many connections from this IP address! */
+ Log(LOG_ERR,
+ "Refused connection from %s: too may connections (%ld) from this IP address!",
+ ip_str, cnt);
+ Simple_Message(new_sock,
+ "ERROR :Connection refused, too many connections from your IP address");
+ close(new_sock);
+ return -1;
+ }
+
+ if (new_sock >= Pool_Size) {
+ if (!array_alloc(&My_ConnArray, sizeof(CONNECTION),
+ (size_t) new_sock)) {
+ Log(LOG_EMERG,
+ "Can't allocate memory! [New_Connection]");
+ Simple_Message(new_sock, "ERROR: Internal error");
+ close(new_sock);
+ return -1;
+ }
+ LogDebug("Bumped connection pool to %ld items (internal: %ld items, %ld bytes)",
+ new_sock, array_length(&My_ConnArray,
+ sizeof(CONNECTION)), array_bytes(&My_ConnArray));
+
+ /* Adjust pointer to new block */
+ My_Connections = array_start(&My_ConnArray);
+ while (Pool_Size <= new_sock)
+ Init_Conn_Struct(Pool_Size++);
+ }
+
+ /* register callback */
+ if (!io_event_create(new_sock, IO_WANTREAD, cb_clientserver)) {
+ Log(LOG_ALERT,
+ "Can't accept connection: io_event_create failed!");
+ Simple_Message(new_sock, "ERROR :Internal error");
+ close(new_sock);
+ return -1;
+ }
+
+ c = Client_NewLocal(new_sock, NULL, CLIENT_UNKNOWN, false);
+ if (!c) {
+ Log(LOG_ALERT,
+ "Can't accept connection: can't create client structure!");
+ Simple_Message(new_sock, "ERROR :Internal error");
+ io_close(new_sock);
+ return -1;
+ }
+
+ Init_Conn_Struct(new_sock);
+ My_Connections[new_sock].sock = new_sock;
+ My_Connections[new_sock].addr = new_addr;
+ My_Connections[new_sock].client = c;
+
+ /* Set initial hostname to IP address. This becomes overwritten when
+ * the DNS lookup is enabled and succeeds, but is used otherwise. */
+ if (ng_ipaddr_af(&new_addr) != AF_INET)
+ snprintf(My_Connections[new_sock].host,
+ sizeof(My_Connections[new_sock].host), "[%s]", ip_str);
+ else
+ strlcpy(My_Connections[new_sock].host, ip_str,
+ sizeof(My_Connections[new_sock].host));
+
+ Client_SetHostname(c, My_Connections[new_sock].host);
+
+ Log(LOG_INFO, "Accepted connection %d from \"%s:%d\" on socket %d.",
+ new_sock, My_Connections[new_sock].host,
+ ng_ipaddr_getport(&new_addr), Sock);
+ Account_Connection();
+
+#ifdef SSL_SUPPORT
+ /* Delay connection initalization until SSL handshake is finished */
+ if (!IsSSL)
+#endif
+ Conn_StartLogin(new_sock);
+
+ return new_sock;
+} /* New_Connection */
+
+
+/**
+ * Finish connection initialization, start resolver subprocess.
+ *
+ * @param Idx Connection index.
+ */
+GLOBAL void
+Conn_StartLogin(CONN_ID Idx)
+{
+ int ident_sock = -1;
+
+ assert(Idx >= 0);
+
+ /* Nothing to do if DNS (and resolver subprocess) is disabled */
+ if (!Conf_DNS)