+
+ len = read( My_Connections[Idx].sock, readbuf, sizeof readbuf -1 );
+ if( len == 0 ) {
+ Log( LOG_INFO, "%s:%d (%s) is closing the connection ...",
+ My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port),
+ inet_ntoa( My_Connections[Idx].addr.sin_addr ));
+ Conn_Close( Idx, "Socket closed!", "Client closed connection", false );
+ return;
+ }
+
+ if( len < 0 ) {
+ if( errno == EAGAIN ) return;
+ Log( LOG_ERR, "Read error on connection %d (socket %d): %s!", Idx,
+ My_Connections[Idx].sock, strerror( errno ));
+ Conn_Close( Idx, "Read error!", "Client closed connection", false );
+ return;
+ }
+#ifdef ZLIB
+ if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
+ if (!array_catb( &My_Connections[Idx].zip.rbuf, readbuf, len)) {
+ Log( LOG_ERR, "Could not append recieved data to zip input buffer (connn %d): %d bytes!", Idx, len );
+ Conn_Close( Idx, "Receive buffer overflow!", NULL, false );
+ return;
+ }
+ } else
+#endif
+ {
+ readbuf[len] = 0;
+ if (!array_cats( &My_Connections[Idx].rbuf, readbuf )) {
+ Log( LOG_ERR, "Could not append recieved data to input buffer (connn %d): %d bytes!", Idx, len );
+ Conn_Close( Idx, "Receive buffer overflow!", NULL, false );
+ }
+ }
+
+ /* Connection-Statistik aktualisieren */
+ My_Connections[Idx].bytes_in += len;
+
+ /* Timestamp aktualisieren */
+ My_Connections[Idx].lastdata = time( NULL );
+
+ Handle_Buffer( Idx );
+} /* Read_Request */
+
+
+static bool
+Handle_Buffer( CONN_ID Idx )
+{
+ /* Handle Data in Connections Read-Buffer.
+ * Return true if a reuqest was handled, false otherwise (also returned on errors). */
+#ifndef STRICT_RFC
+ char *ptr1, *ptr2;
+#endif
+ char *ptr;
+ int len, delta;
+ bool action, result;
+#ifdef ZLIB
+ bool old_z;
+#endif
+
+ result = false;
+ do {
+ /* Check penalty */
+ if( My_Connections[Idx].delaytime > time( NULL )) return result;
+#ifdef ZLIB
+ /* unpack compressed data */
+ if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP ))
+ if( ! Unzip_Buffer( Idx )) return false;
+#endif
+
+ if (0 == array_bytes(&My_Connections[Idx].rbuf))
+ break;
+
+ if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) /* make sure buf is NULL terminated */
+ return false;
+
+ /* A Complete Request end with CR+LF, see RFC 2812. */
+ ptr = strstr( array_start(&My_Connections[Idx].rbuf), "\r\n" );
+
+ if( ptr ) delta = 2; /* complete request */
+#ifndef STRICT_RFC
+ else {
+ /* Check for non-RFC-compliant request (only CR or LF)? Unfortunately,
+ * there are quite a few clients that do this (incl. "mIRC" :-( */
+ ptr1 = strchr( array_start(&My_Connections[Idx].rbuf), '\r' );
+ ptr2 = strchr( array_start(&My_Connections[Idx].rbuf), '\n' );
+ delta = 1;
+ if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1;
+ else if( ptr1 ) ptr = ptr1;
+ else if( ptr2 ) ptr = ptr2;
+ }
+#endif
+
+ action = false;
+ if( ! ptr )
+ break;
+
+ /* End of request found */
+ *ptr = '\0';
+
+ len = ( ptr - (char*) array_start(&My_Connections[Idx].rbuf)) + delta;
+
+ if( len < 0 || len > ( COMMAND_LEN - 1 )) {
+ /* Request must not exceed 512 chars (incl. CR+LF!), see
+ * RFC 2812. Disconnect Client if this happens. */
+ Log( LOG_ERR, "Request too long (connection %d): %d bytes (max. %d expected)!",
+ Idx, array_bytes(&My_Connections[Idx].rbuf), COMMAND_LEN - 1 );
+ Conn_Close( Idx, NULL, "Request too long", true );
+ return false;
+ }
+
+#ifdef ZLIB
+ /* remember if stream is already compressed */
+ old_z = My_Connections[Idx].options & CONN_ZIP;
+#endif
+
+ if( len > delta )
+ {
+ /* A Request was read */
+ My_Connections[Idx].msg_in++;
+ if( ! Parse_Request( Idx, (char*)array_start(&My_Connections[Idx].rbuf) )) return false;
+ else action = true;
+
+ array_moveleft(&My_Connections[Idx].rbuf, 1, len);
+#ifdef DEBUG
+ Log(LOG_DEBUG, "%d byte left in rbuf", array_bytes(&My_Connections[Idx].rbuf));
+#endif
+ }
+
+#ifdef ZLIB
+ if(( ! old_z ) && ( My_Connections[Idx].options & CONN_ZIP ) && ( array_bytes(&My_Connections[Idx].rbuf) > 0 ))
+ {
+ /* The last Command activated Socket-Compression.
+ * Data that was read after that needs to be copied to Unzip-buf
+ * for decompression */
+ if( array_bytes(&My_Connections[Idx].rbuf)> ZREADBUFFER_LEN ) {
+ /* No space left */
+ Log( LOG_ALERT, "Can't move receive buffer: No space left in unzip buffer (need %d bytes)!", array_bytes(&My_Connections[Idx].rbuf ));
+ return false;
+ }
+ if (!array_copy( &My_Connections[Idx].zip.rbuf, &My_Connections[Idx].rbuf ))
+ return false;
+
+ array_trunc(&My_Connections[Idx].rbuf);
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Moved already received data (%d bytes) to uncompression buffer.", array_bytes(&My_Connections[Idx].zip.rbuf));
+#endif /* DEBUG */
+ }
+#endif /* ZLIB */
+ if( action ) result = true;
+ } while( action );
+
+ return result;
+} /* Handle_Buffer */
+
+
+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;
+
+ for( i = 0; i < Pool_Size; i++ ) {
+ if( My_Connections[i].sock == NONE ) continue;
+
+ c = Client_GetFromConn( i );
+ if( c && (( Client_Type( c ) == CLIENT_USER ) || ( Client_Type( c ) == CLIENT_SERVER ) || ( Client_Type( c ) == CLIENT_SERVICE )))
+ {
+ /* connected User, Server or Service */
+ if( My_Connections[i].lastping > My_Connections[i].lastdata ) {
+ /* we already sent a ping */
+ if( My_Connections[i].lastping < time( NULL ) - Conf_PongTimeout ) {
+ /* Timeout */
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Connection %d: Ping timeout: %d seconds.", i, Conf_PongTimeout );
+#endif
+ Conn_Close( i, NULL, "Ping timeout", true );
+ }
+ }
+ else if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout ) {
+ /* we need to sent a PING */
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Connection %d: sending PING ...", i );
+#endif
+ My_Connections[i].lastping = time( NULL );
+ Conn_WriteStr( i, "PING :%s", Client_ID( Client_ThisServer( )));
+ }
+ }
+ else
+ {
+ /* connection is not fully established yet */
+ if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout )
+ {
+ /* Timeout */
+#ifdef DEBUG
+ Log( LOG_DEBUG, "Connection %d timed out ...", i );
+#endif
+ Conn_Close( i, NULL, "Timeout", false );
+ }
+ }
+ }
+} /* Check_Connections */
+
+
+static void
+Check_Servers( void )
+{
+ /* Check if we can establish further server links */
+
+ RES_STAT *s;
+ CONN_ID idx;
+ int i, n;
+
+ /* Serach all connections, are there results from the resolver? */
+ for( idx = 0; idx < Pool_Size; idx++ )
+ {
+ if( My_Connections[idx].sock != SERVER_WAIT ) continue;
+
+ /* IP resolved? */
+ if( My_Connections[idx].res_stat == NULL ) New_Server( Conf_GetServer( idx ), idx );
+ }
+
+ /* Check all configured servers */
+ for( i = 0; i < MAX_SERVERS; i++ )