#!/usr/bin/perl -I/srv/server/phexproxy/PhexProxy

#########################################
##### Author:		Sebastian Enger / B.Sc
##### CopyRight:	BitJoe GmbH
##### LastModified	5.03.2007
##### Function:		Hauptdatei für PhexProxy
##### Todo:			for statt foreach: ist schneller
########################################

system("renice 20 $$");
system("clear");

# todo: connection counter - nach 5 mal keine ergebnisse bemühe den result cache
# connection request daten abholen: 20s, 10s, 10s, 7s, 5s, public result cache

#### TODO: zuerst müssen alle Perl Phex Paris Server laufen und dann erst $0 starten !!! ####

# caching von ergebnissen einbauen mittels tie(%ParisSocketsHash, 'DB_File', $DBFlatFile)
# und caching einträge dann mittels my $cache = $DistributedCache{'paris .jpg'}; 
# aber dann auch noch $ParisSocketsHash{'NULLRESULTENTRYCOUNT'.$COUNT.$MD5}	= $count++; einführen: sprich wieoft wurden schon erfolglos ergebnisse abgeholt

# auf dem Cleron Phex Proxy werden die Ergebnisse komprimiert ausgegeben
### Blocking(0) einstellen bei IO

use constant VERSION	=> "PhexDistributedProxy 0.9.6.6 - 18.10.2007 @ 17.15 Uhr";
use constant PIDFILE	=> "/server/phexproxy/phexdistributedproxygzip-pid.txt";

use constant CRLF		=> "\r\n";
use constant SEPARATOR	=> "##";


use strict;
use DB_File;
use IO::Select;
use POSIX qw(floor ceil);
use Data::Dumper;
use PhexProxy::IO;
use PhexProxy::Gzip;
use PhexProxy::Time;
use PhexProxy::Daemon;
use PhexProxy::CheckSum;
use PhexProxy::CryptoLibrary;
use PhexProxy::SortArray qw( Sort_Table );

# use Data::Dumper;

my $HandyClientIPAdress;
my $HandyClientHostName;
my $HandyClientSocket;


my %ParisHosts				= (
	"127.0.0.1"				=> "3385",
#	"81.169.141.129"		=> "3385",
);

my $DONE					= 0;

my $port					= 7773;	# Port von Programm $0
my $MaxResults				= 10;	# 10 Ergebnisse für den HandyClient
my $MaxSourcesForOneResult	= 15;	# Max Quellen pro Ergebnis
my $MaxNoResultTries		= 4;	# nach maximal 3 erfolglosen versuchen wird versucht einen eintrag aus dem Cache zu lesen
my $MaxCacheValidTime		= 60;	# in sekunden
my $ParisHostCount			= keys( %ParisHosts );
my $ParisSocketsHashRef		= ();

my %ParisSocketsHash		= ();
my $ParisSocketsHash		= ();

my %ParisResultCache		= ();
my $ParisResultCache		= ();

my $DBFlatFile				= "/server/phexproxy/tmp/connections.db"; unlink $DBFlatFile || system("/bin/rm -rf $DBFlatFile");
my $ResultCacheFile			= "/server/phexproxy/cache/DistributedResultCache.db";
my $TakeResultsPerHost		= floor( $MaxResults / $ParisHostCount );

if ( $TakeResultsPerHost <= 0 ) {
	$TakeResultsPerHost = 1;
};

my $IO			= PhexProxy::IO->new();
my $GZIP		= PhexProxy::Gzip->new();
my $TIME		= PhexProxy::Time->new();
my $CHECK		= PhexProxy::CheckSum->new();
my $CRYPTO		= PhexProxy::CryptoLibrary->new();

my $Socket		= PhexProxy::IO->CreateHandyDistributedSocket( $port );
my $IN			= IO::Select->new($Socket);

unlink PIDFILE;
#&init_server(PIDFILE);

die "can't setup $0 socket" unless $Socket;
print "[Server $0 Version " . VERSION . " accepting clients on port $port]\n";

########################
##### while accept loop
########################

while (!$DONE) {

	tie(%ParisSocketsHash, 'DB_File', $DBFlatFile) || die "can't open $DBFlatFile: $!";

	next unless $IN->can_read;
	next unless $HandyClientSocket	= $Socket->accept();
	$HandyClientIPAdress			= $HandyClientSocket->sockhost;
	my $MD5							= $CHECK->MD5ToHEX($HandyClientIPAdress);

	my $child						= launch_child();
	
	unless ($child) {

		close $Socket;

		# erstelle den socket zum paris programm 
		my $COUNT = 0;

		while( my ($host,$port) = each(%ParisHosts)){

			next if ( $COUNT > ($ParisHostCount - 1));
			my $ParisSocket = PhexProxy::IO->CreateSocketToParis( $host,$port );
			if ( ref($ParisSocket) eq "IO::Socket::INET" ) { 
			
				$ParisSocketsHashRef->{$COUNT}->{'HOST'}	= $host;			# diese werte werden im verlauf genutzt
				$ParisSocketsHashRef->{$COUNT}->{'SOCKET'}	= $ParisSocket;
		
				# wenn ich an jedes Hash in connections.db noch eine unique id ranhänge, dann ist diese version multiconnect-fähig, 
				# da zu jeder IP der MD5 gebildet wird und dieser MD5 unique im Hash dann genutzt wird
				
				$ParisSocketsHash{'HOST'.$COUNT.$MD5}			= $host;			# diese werte werden im verlauf nicht genutzt
				$ParisSocketsHash{'SOCKET'.$COUNT.$MD5}			= $ParisSocket;
				$ParisSocketsHash{'NOCRESULTCOUNT'.$COUNT.$MD5}	= 0;

				$COUNT++;

			}; # if ( ref($ParisSocket) eq "IO::Socket::INET" ) { 

		 }; # while( my($host,$port) = each(%ParisHosts)){	

		$COUNT -= 1;	# because from the while( my ($host,$port) = each(%ParisHosts)){ the COUNT goes up to 2, but later we start counting from 0 instead from 1 therefore here -1

		if ( $COUNT == 0 ) {
			$COUNT = ( keys( %ParisSocketsHash ) / keys( %ParisHosts ) ) - 1;	# -1 : because in the following programm we start to count at 0 and not at 1 !
		}; # if ( $COUNT == 0 ) {
 
		# print Dumper %ParisSocketsHash; 
		# print $ParisSocketsHash{'HOST'.$COUNT}; exit;

		# Nehme den Content vom Handy an
		my $ReadFromClient		= $IO->readSocket( $HandyClientSocket );
		my $ReadFromClientOrg	= $ReadFromClient;

		my @ReadFromClient		= split('##', $ReadFromClient );
		my $CurTime				= $TIME->MySQLDateTime();

		####################### crypto api implementatione #####################
		#	$IOReadFromClient[0] = MD5 Wert der Verschlüsselten Nachricht
		#	$IOReadFromClient[1] = der public schlüssel 
		#	$IOReadFromClient[2] = die verschlüsselte nachricht
			

		my $PrivateCryptoKey = $CRYPTO->GetPrivateCryptoKeyFromDatabase( $ReadFromClient[1] );
		if ( $PrivateCryptoKey == -1 ) {
		
			print STDERR "Error: Crypto false privatekey - got: '$ReadFromClient[1]'\n";
			print Dumper $ReadFromClient;
			$IO->writeSocket($HandyClientSocket, $GZIP->gzip_compress_string("Crypto false privatekey") . CRLF);
			exit(0);

		}; # if ( $PrivateKey == -1 ) {}

		my $PlainText				= $CRYPTO->Decrypt( $PrivateCryptoKey, $ReadFromClient[2] );
		my @IOReadFromClient		= ();		# resette das wichtige Array
	
		my ( $stuff			)		= split("\r\n", $PlainText ); 
		my ( @IOReadFromClient )	= split("##", $stuff ); 

		if ( $IOReadFromClient[0] eq 'find' ) {
			
			printf STDOUT "[ Connect from $HandyClientIPAdress at $CurTime ] - Submitting Search '$IOReadFromClient[5] .$IOReadFromClient[1]' to Phex\n";

			#### Verteile die Anfragen an alle Phex Proxys
			my $COUNT = 0;

			for ( %ParisSocketsHash ){	

				my $ParisSocket = $ParisSocketsHashRef->{$COUNT}->{'SOCKET'};	# ACCESS A HASHREF	
				next if ( ref($ParisSocket) ne "IO::Socket::INET" );

				$IO->writeSocket( $ParisSocket , $ReadFromClientOrg );			# suchanfrage des handys direkt an paris.pl weiterreichen	
				my $CompressedQueryID	= $IO->readSocket( $ParisSocket );		# komprimierte query id abholen ...
				$CompressedQueryID		=~ s/CRLF//ig;
			
				# old $ParisSocketsHash{'QUERYID'.$COUNT.$MD5}	= $GZIP->gzip_decompress_string( $TempQueryId );	# speichere den QueryID
				$CompressedQueryID		= $GZIP->gzip_decompress_string( $CompressedQueryID );
				$ParisSocketsHash{'QUERYID'.$COUNT.$MD5}		= $CompressedQueryID;	# speichere den QueryID
				$IO->writeSocket( $HandyClientSocket , $GZIP->gzip_compress_string($CompressedQueryID) );	# ... und an das Handy weitereichen
				
				$COUNT++;

			}; # for ( %ParisSocketsHash ){		

		} elsif ( $IOReadFromClient[0] eq 'result' ){
	
			# todo: wenn ein host schon ergebnisse geliefert hat, der andere noch nicht, dann nochmal so lange ca 4 mal den anderen zum abholen bewegen!!!

			printf STDOUT "[ Connect from $HandyClientIPAdress at $CurTime ] - Serving Request for Query: '$IOReadFromClient[5]' \n";	
			
			# Stelle die Result-Anfrage an jeden Paris Server
			my $COUNT = 0;

			for ( %ParisSocketsHash ){	
				
				####################### crypto api implementatione #####################
				#	$IOReadFromClient[0] = MD5 Wert der Verschlüsselten Nachricht
				#	$IOReadFromClient[1] = der public schlüssel 
				#	$IOReadFromClient[2] = die verschlüsselte nachricht

				my $ParisSocket							= $ParisSocketsHashRef->{$COUNT}->{'SOCKET'};
				next if ( ref($ParisSocket) ne "IO::Socket::INET" );

				my $QueryID								= $ParisSocketsHash{'QUERYID'.$COUNT.$MD5};
				$IOReadFromClient[6]					= $QueryID;
				my $FinalResultString					= join("##", @IOReadFromClient );
				$FinalResultString						.= CRLF;
		
				my $PublicCryptoKey						= $ReadFromClient[1];
				my $CryptoText							= $CRYPTO->Encrypt( $PrivateCryptoKey, $FinalResultString );
				my $CryptoTextMD5						= $CHECK->MD5ToHEX($CryptoText);
				my $FinalResultSendString				= "$CryptoTextMD5##$PublicCryptoKey##$CryptoText" . CRLF;
					
				$IO->writeSocket( $ParisSocket , $FinalResultSendString );		# suchanfrage des handys direkt an paris.pl weiterreichen	
	
				my $TempString = ""; my $buffIO = "";
				
				while (sysread($ParisSocket, $buffIO, 1) == 1) {
					$TempString .= $buffIO;
				}; # while

				$TempString		=~ s/CRLF//ig;
				$TempString		= $GZIP->gzip_decompress_string( $TempString );
			
				if ( length($TempString) => 10) {
					$ParisSocketsHash{'RESULTS'.$COUNT.$MD5} = $TempString;
				} else {
					$ParisSocketsHash{'NOCRESULTCOUNT'.$COUNT.$MD5}	= $ParisSocketsHash{'NOCRESULTCOUNT'.$COUNT.$MD5} + 1;
				};

				$COUNT++;

			}; # for ( %ParisSocketsHash ){	

			#### START: Setze die Ergebnisse zusammen, nimm dazu von jedem Paris Ergebnishost die Liste und nimm davon genau $TakeResultsPerHost Ergebnisse
			
			# ergebnistrenner ist CRLF der ganze code mit dem sortieren via sortarray funzt nicht, da die results nicht mehr an ### sondern an CRLF getrennt werden

			my @AllResultContent	= ();
			my $COUNT				= 0;
		
			for ( %ParisSocketsHash ){	
				
				my $TempResultString = $ParisSocketsHash{'RESULTS'.$COUNT.$MD5};
				
	#			my $TempResultString =~ s/\r\n/##/; 
	#			my @ResultContent	 = split("\t\t", $TempResultString );
	#			my @ResultContent	 = split("##", $TempResultString );
	#			
	#			print "REsultContent: @ResultContent \n";
	#			next if ( $#ResultContent <= 0 );
				push(@AllResultContent, split("\r\n", $TempResultString) ) if ( length($TempResultString) > 10 );
			
				$COUNT++;
	
			}; # for ( %ParisSocketsHash ){	
	
	#		# new: 19.10.2007
	#		my %seen = ();
	#		@AllResultContent = grep { ! $seen{$_} ++ } @AllResultContent;
	#			
	#
	#		# Sortierung nach Rank
	#		my @SORTED = Sort_Table(
	#			cols      => '4',
	#			field     => '1',
	#			sorting   => 'descending',
	#			structure => 'csv',
	#		#	separator => '###',
	#			separator => "\r\n",
	#			data      => \@AllResultContent,
	#		);


			### algo:
			# if $AllResultContent[1] kleiner $AllResultContent[2] dann ist 1=rank und 2=size
			# if $AllResultContent[3] length == 32 dann sha1
			# if $AllResultContent[4] =~ /^((25[0-4]|(2[0-4]|1[0-9]|[1-9]?)[0-9]\.){3}(25[0-4]|(2[0-4]|1[0-9]|[1-9]?)[0-9]))+(\:)([0-9]{1,})$/ dann peer
			

			my @SORTED		= ();
			my $tempCount	= 0;
			my $tempEntry	= "";

			open(WH,">/server/phexproxy/sorted_temp.txt");
	
			for ( my $i=0; $i<=$#AllResultContent; $i++ ) {
			
				my $entry	= $AllResultContent[$i];
				my $strlen	= length($entry);
				next if ( $strlen == 0 );	
				chomp($entry);
			
				if( $tempCount == 0 ) {
					$tempEntry .= "$entry##";
					print WH "[$strlen] Entry RANK: '$entry'\n";

				} elsif( $tempCount == 1 ) {
					$tempEntry .= "$entry##";
					print WH "[$strlen] Entry SIZE: '$entry'\n";

				} elsif( $tempCount == 2 ) {
					$tempEntry .= "$entry##";
					print WH "[$strlen] Entry SHA1: '$entry'\n";

				} elsif( $tempCount == 3 ) {
				
					if ( $AllResultContent[$i+1] =~ /^((25[0-4]|(2[0-4]|1[0-9]|[1-9]?)[0-9]\.){3}(25[0-4]|(2[0-4]|1[0-9]|[1-9]?)[0-9]))+(\:)([0-9]{1,})$/ ) {
						$tempCount = 2;	# damit beim nächsten durchgang wieder die anweisung für } elsif( $tempCount == 3 ) { aufgerufen wird
						$tempEntry .= $entry . CRLF;
					} else {
						$tempEntry .= "$entry##";
					};

					push(@SORTED, "$tempEntry\n");
					print WH "[$strlen] Entry PEER: '$entry'\n";

					$tempEntry = "";
					$tempCount = 0;
		

				};

				$tempCount++;

			};

			close WH;


		#	open(WH,">/server/phexproxy/sorted_temp.txt");
		#		print WH Dumper @SORTED;
		#	close WH;
			

			# diese foreach schleife bringt die ergebnisse des arrays @SORTED in passende form für den Hash hinter $SortedHashRef

			my $SortedHashRefCount	= 0;
			my $SortedHashRef		= {};

			foreach my $content ( @SORTED ) {
				
				my ( $RANK, $SIZE, $SHA1, $PEERHOST ) = split("##", $content );
				
				# print "ONE: '$RANK, $SIZE, $SHA1, $PEERHOST' \n"; exit;

				if ( length($RANK) > 0 && length($SIZE) > 0 && length($SHA1) == 32 && length($PEERHOST) > 0 ) {
				
					$SortedHashRef->{ $SortedHashRefCount }->{ 'SZ' } = $SIZE;
					$SortedHashRef->{ $SortedHashRefCount }->{ 'SH' } = $SHA1;
					$SortedHashRef->{ $SortedHashRefCount }->{ 'RK' } = $RANK;
					$SortedHashRef->{ $SortedHashRefCount }->{ 'PH' } = $PEERHOST;
					
					$SortedHashRefCount++;

				}; # if ( length($RANK) > 0 && length($SIZE) > 0 && length($SHA1) == 32 && length($PEERHOST) > 0 ) {

			}; # foreach my $content ( @ResultContent ) {


			# in den folgenden 2 for schleifen werden die ergebnisse anhand gleicher SHA1 werte zusammengefasst und die quellen von den einzelnen Paris Ergebnisse ineinander integriert
			my $SortHashRefCount = keys(%{$SortedHashRef});
	
			for ( my $Key=0; $Key<=$SortHashRefCount; $Key++ ) {

				my $SHA1			= %{$SortedHashRef}->{ $Key }->{ 'SH' };
				my $Size			= %{$SortedHashRef}->{ $Key }->{ 'SZ' };
				my $PeerHost		= %{$SortedHashRef}->{ $Key }->{ 'PH' };
				my $Rank			= %{$SortedHashRef}->{ $Key }->{ 'RK' };

				for ( my $NextKey=0; $NextKey<=$SortHashRefCount; $NextKey++ ) {

					my $SHA1Next		= %{$SortedHashRef}->{ $NextKey }->{ 'SH' };
					my $SizeNext		= %{$SortedHashRef}->{ $NextKey }->{ 'SZ' };
					my $PeerHostNext	= %{$SortedHashRef}->{ $NextKey }->{ 'PH' };
					my $RankNext		= %{$SortedHashRef}->{ $NextKey }->{ 'RK' };

					if ( ($SHA1 eq $SHA1Next) && length($SHA1) == 32 && length($SHA1Next) == 32 ) {

						my @PEERSNEXT	= split("\r\n",$PeerHostNext );
						my @PEERS		= split("\r\n",$PeerHost );

						# füge von Anzahl der Einträge in Peers bis zum Wert $MaxSourcesForOneResult noch werte aus PeerHostNext zu PeerHost dazu
						my $StartAtSource = 0;

						for ( my $i=$#PEERS; $i<=$MaxSourcesForOneResult; $i++ ) {
		
							# später next if ( $#PEERS >= $MaxSourcesForOneResult ); 
							# später: wenn $PEERSNEXT[$StartAtSource] kein gültiges Ergebnis liefert, dann nimm eins aus dem Array, dass eins liefert
							$SortedHashRef->{ $Key }->{ 'PH' } .= $PEERSNEXT[$StartAtSource] . "\r\n" if ( length($PEERSNEXT[$StartAtSource]) >= 20 && lc($SortedHashRef->{ $Key }->{ 'PH' }) ne lc($PEERSNEXT[$StartAtSource]) );
							$StartAtSource++ if ( length($PEERSNEXT[$StartAtSource]) >= 20 && lc($SortedHashRef->{ $Key }->{ 'PH' }) ne lc($PEERSNEXT[$StartAtSource]) );

							# eventuell noch einbauchen dass $SortedHashRef->{ $Key }->{ 'PH' } jeder einzelne eintrag davon als Peer extrahiert wird und in ein HashRef geschrieben wird,
							# dann dieses nehmen und checken, ob der eintrag $PEERSNEXT[$StartAtSource] schon als eintrag im HashRef 


						}; # for ( my $i=$#PEERS; $i<=$MaxSourcesForOneResult; $i++ ) {
					
						# schalge einen prozentualen teil der punkte von PeerNext auf Peer auf
						my $AddPointsToRank = 0;
						$AddPointsToRank	= ceil( $RankNext / $StartAtSource ) if ( $RankNext > 0 && $StartAtSource > 0 );		# ceil Runde die Punkte auf / Divison durch Null Bug- Lösung
						$SortedHashRef->{ $Key }->{ 'RK' } += $AddPointsToRank if ( $StartAtSource > 0 );

						# !!! Wichtig: in $SortedHashRef wird KEIN EINTRAG gelöscht, wir lösen das problem der 
						# eventuellen doppelten einträge später in der Result Ausgabe mit einem if exits HashRef->SHA1!

					}; # if ( ($SHA1 eq $SHA1Next) && length($SHA1) == 32 && length($SHA1Next) == 32 ) {

				}; # for ( my $NextKey=0; $NextKey<=$SortHashRefCount; $NextKey++ ) {

			}; # for ( my $Key=0; $Key<=$SortHashRefCount; $Key++ ) {

			# Öffne die ResultCache DB
			tie(%ParisResultCache, 'DB_File', $ResultCacheFile ) || die "can't open $ResultCacheFile: $!";
			
			my $CacheEntry				= lc("$IOReadFromClient[5] .$IOReadFromClient[1]");					# dies ist unser cache hash key, zb. "paris .b0"
			my $CacheEntryCreateTime	= $CacheEntry . "-created";											# dies ist unser cache timestamp hash key

			# folgende foreach schleife setzt die ergebnisse für das handy zusammen

			my $SendString				= "";	# Dies ist der String mit den finalen Ergebnissen für das Handy	
			my $FinalResultCount		= 0;
			my $NoDoubleEntryHashRef	= {};

			foreach my $Key ( sort { $SortedHashRef->{$b}->{'RK'} <=> $SortedHashRef->{$a}->{'RK'} } keys %{$SortedHashRef} ) {
				
				my $SHA1			= %{$SortedHashRef}->{ $Key }->{ 'SH' };
				my $Size			= %{$SortedHashRef}->{ $Key }->{ 'SZ' };
				my $PeerHost		= %{$SortedHashRef}->{ $Key }->{ 'PH' };
				my $Rank			= %{$SortedHashRef}->{ $Key }->{ 'RK' };
				
				next if ( exists( $NoDoubleEntryHashRef->{$SHA1} ) || $FinalResultCount > $MaxResults );	# hier keine doppelten einträge(2 gleiche SHA1-werte) mehr anzeigen lassen

				$SendString			.= $Rank .CRLF. $Size .CRLF. $SHA1 .CRLF. $PeerHost .CRLF;

				# schreibe den ResultCache in die FlatFileDB
				if ( length($SendString) >= 50 ) {
					$ParisResultCache{$CacheEntry}				= $SendString;
					$ParisResultCache{$CacheEntryCreateTime}	= time();
				};

				my $SizeKB	= ( $Size / 1024 );
				my $SizeMB	= ( $SizeKB / 1024 );
		
			
				if ( keys( %{$SortedHashRef} ) > 1 ) {
				
					print "Entry: $FinalResultCount \n";
					print "DEBUG: SIZE: '$Size' Bytes und $SizeKB KB| $SizeMB MB \n";
					print "DEBUG: RANK: $Rank\n";
					print "DEBUG: SHA1: $SHA1\n";
					print "DEBUG: PeerHost: $PeerHost\n";
					print "############ \n";

				};
			
				$NoDoubleEntryHashRef->{$SHA1} = "";
				$FinalResultCount++;

			}; # foreach my $entry ( sort

			#### END: Setze die Ergebnisse zusammen, nimm dazu von jedem Paris Ergebnishost die Liste und nimm davon genau $TakeResultsPerHost Ergebnisse

		
			# bestimme 
			my $COUNT			= 0;
			my $NoResultCounter	= 0;
			for ( %ParisSocketsHash ){	

				$NoResultCounter += $ParisSocketsHash{'NOCRESULTCOUNT'.$COUNT.$MD5};
				$COUNT++;

			}; # for ( %ParisSocketsHash ){	

			my $CacheCreateTime			= $ParisResultCache{$CacheEntryCreateTime};				# wann wurde cache erstellt
			my $CacheDifferTime			= time() - $CacheCreateTime;							# differenz zwischen aktuellem zeitpunkt und dem punkt der erstellung des caches
			my $NoResultEntryTriesFlag	= ( $NoResultCounter / keys( %ParisHosts ) );	# wie oft wurde pro vorhandenem paris host schonmal erfolglos versucht ergebnisse auszuliefern ?

			# wenn mehr als $MaxNoResultTries erfolglos versucht wurde ein ergebniss auszuliefern und
			# der cache zeittechnisch noch gültig ist, dh unter $MaxCacheValidTime sek liegt, dann versuche einen cache hit
			if ( $NoResultEntryTriesFlag >= $MaxNoResultTries && $CacheDifferTime <= $MaxCacheValidTime && length($SendString) <= 50 ) {
				print "Cache hit for: '$CacheEntry' \n"; sleep 4;
				$SendString = $ParisResultCache{$CacheEntry};
			};

		#	my $leng = length($SendString);
		#	print "Sendsting is $leng long \n";
			
			# schreibe dem handyclient den gezippten string!!!!
			if ( length($SendString) >= 30 ) {
				$IO->writeSocket($HandyClientSocket, $GZIP->gzip_compress_string($SendString) . CRLF );
			} else {
				$IO->writeSocket($HandyClientSocket, $GZIP->gzip_compress_string("FC 808") . CRLF );
			};

			# resette die flat file tabelle  für den bestimmten und grade bearbeiteten eintrag, wenn mehr als 2 ergebnisse ausgeliefert wurden
			if ( $FinalResultCount >= 5 ) {

				my $COUNT = 0;
		
				for ( %ParisSocketsHash ){	
				
					$ParisSocketsHash{'HOST'.$COUNT.$MD5}			= "";	
					$ParisSocketsHash{'SOCKET'.$COUNT.$MD5}			= "";	
					$ParisSocketsHash{'QUERYID'.$COUNT.$MD5}		= "";	
					$ParisSocketsHash{'RESULTS'.$COUNT.$MD5}		= "";	
					$ParisSocketsHash{'NOCRESULTCOUNT'.$COUNT.$MD5}	= "";

					$COUNT++;

				}; # for ( %ParisSocketsHash ){	
			
			}; # if ( $FinalResultCount >= 2 ) {

		}; # if ( $ReadFromClient[0] eq 'find' ) { # } elsif ( $IOReadFromClient[0] eq 'result' ){
		
	
		###### Schließe alle Sockets
		my $COUNT = 0;
		
		for ( %ParisSocketsHash ){	

			next if ( ref( $ParisSocketsHashRef->{$COUNT}->{'SOCKET'} ) ne "IO::Socket::INET" );
			close $ParisSocketsHashRef->{$COUNT}->{'SOCKET'};

			$COUNT++;

		}; # for ( %ParisSocketsHash ){	

		# schließe die ResultCache DB und beended das Programm
		untie(%ParisResultCache);
		exit(0);

	}; #  unless ($child) {}

	# schließe HandySocket und die Connections Datenbank
	close $HandyClientSocket;
	untie(%ParisSocketsHash);

}; # while (!$DONE) {}

########################
##### while accept loop
########################

die "$0 - Normal termination\n";
exit(0);

### my $ParisSocket = $ParisSocketsHashRef->{$COUNT}->{'SOCKET'};			# ACCESS A HASHREF
### DOESNT WORK! my $ParisSocket = $ParisSocketsHash{'SOCKET'.$COUNT};		# Access a HASH



#SearchString = "find"+"##"+
#      Constant.SELECTED_FILE_FAMILY+","+Constant.SELECTED_FILE_TYPE+"##"+
#      "IMEI"+"##"+
#      Constant.LIZENZ_KEY+"##"+
#      Constant.VERSION+"##"+
#      to_search+"##"+
#      "JAVAVERSION"+"##"+
#      "HandyModell"+"##"+
#     "PROVIDER"+"\r\n";
 
#zweitens resultat abholen:
 
#resultString = "result"+"##"+
#      Constant.SELECTED_FILE_FAMILY+","+Constant.SELECTED_FILE_TYPE+"##"+
#      "IMEI"+"##"+
#      Constant.LIZENZ_KEY+"##"+
#      Constant.VERSION+"##"+
#      to_search+"##"+
#      id+"##"+"\r\n";

