2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-28 11:01:59 +00:00

PRESENCE/collectord: fix perl warning (Forum: #84243)

git-svn-id: https://svn.fhem.de/fhem/trunk@16171 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
markusbloch 2018-02-13 21:37:47 +00:00
parent 3abd49a0c1
commit a2609b315c

View File

@ -72,12 +72,10 @@ my %handle;
my %socket_to_handle; my %socket_to_handle;
$SIG{__DIE__} = sub { $SIG{__DIE__} = sub {
my ($msg) = @_; my ($msg) = @_;
Log 1, "PERL ERROR: $msg"; Log 1, "PERL ERROR: $msg";
}; };
@ -85,7 +83,6 @@ $SIG{__WARN__} = sub {
my ($msg) = @_; my ($msg) = @_;
Log 1, "PERL WARN: $msg"; Log 1, "PERL WARN: $msg";
}; };
@ -118,7 +115,7 @@ sub print_usage () {
print " -d, --daemon\n"; print " -d, --daemon\n";
print " detach from terminal and run as background daemon\n"; print " detach from terminal and run as background daemon\n";
print " -n, --no-timestamps\n"; print " -n, --no-timestamps\n";
print " do not output timestamps in log messages\n"; print " do not output timestamps in log messages\n";
print " -v, --verbose\n"; print " -v, --verbose\n";
print " Print detailed log output (can be used multiple times to increase the loglevel, max. 2 times)\n"; print " Print detailed log output (can be used multiple times to increase the loglevel, max. 2 times)\n";
print " -l, --logfile <logfile>\n"; print " -l, --logfile <logfile>\n";
@ -145,16 +142,12 @@ if(not $opt_c)
print STDERR "no config file provided\n\n"; print STDERR "no config file provided\n\n";
print_usage(); print_usage();
exit 1; exit 1;
} }
if(not -e "$opt_c" or not -r "$opt_c") if(not -e "$opt_c" or not -r "$opt_c")
{ {
print STDERR "config-file $opt_c could not be loaded\n"; print STDERR "config-file $opt_c could not be loaded\n";
exit 1; exit 1;
} }
Log 0, "started with PID $$"; Log 0, "started with PID $$";
@ -186,8 +179,6 @@ Log 1, "created socket on ".$server->sockhost()." with port ".$server->sockport(
my $listener = IO::Select->new(); my $listener = IO::Select->new();
$listener->add($server); $listener->add($server);
my @new_handles; my @new_handles;
my %child_handles; my %child_handles;
my %child_config; my %child_config;
@ -228,20 +219,19 @@ while(1)
Log 2, "cleaning up status values (UUID: $uuid)"; Log 2, "cleaning up status values (UUID: $uuid)";
delete $state{$uuid}; delete $state{$uuid};
} }
} }
# process all status messages from all threads via status queue # process all status messages from all threads via status queue
while($status_queue->pending) while($status_queue->pending)
{ {
my ($uuid,$room,$value,$data) = split(";", $status_queue->dequeue, 4); my ($uuid,$room,$value,$data) = split(";", $status_queue->dequeue, 4);
Log 2, "processing state message for device ".(defined($name)?$name." ":"")."in room $room (UUID: $uuid) - value: $value".(defined($data) ? " - data: $data" : ""); Log 2, "processing state message for device ".(defined($name)?$name." ":"")."in room $room (UUID: $uuid) - value: $value".(defined($data) ? " - data: $data" : "");
if(not $value =~ /^(absence|present)$/) if(not $value =~ /^(absence|present)$/)
{ {
$handle{$uuid}{client}->send("$value;room=$room\n") if(defined($handle{$uuid}{client})); $handle{$uuid}{client}->send("$value;room=$room\n") if(defined($handle{$uuid}{client}));
if($value eq "socket_closed") if($value eq "socket_closed")
{ {
delete($state{$uuid}{rooms}{$room}); delete($state{$uuid}{rooms}{$room});
@ -250,7 +240,7 @@ while(1)
else else
{ {
$state{$uuid}{rooms}{$room}{state} = $value; $state{$uuid}{rooms}{$room}{state} = $value;
if(defined($data)) if(defined($data))
{ {
$state{$uuid}{rooms}{$room}{data} = $data; $state{$uuid}{rooms}{$room}{data} = $data;
@ -259,9 +249,9 @@ while(1)
{ {
delete $state{$uuid}{rooms}{$room}{data}; delete $state{$uuid}{rooms}{$room}{data};
} }
my $result = aggregateRooms($state{$uuid}{rooms}); my $result = aggregateRooms($state{$uuid}{rooms});
if(defined($result)) if(defined($result))
{ {
if(not defined($state{$uuid}{lastresult}{value}) or (($state{$uuid}{lastresult}{value} eq "$result" and ($state{$uuid}{lastresult}{timestamp} + $handle{$uuid}{timeout}) < time()) or $state{$uuid}{lastresult}{value} ne "$result")) if(not defined($state{$uuid}{lastresult}{value}) or (($state{$uuid}{lastresult}{value} eq "$result" and ($state{$uuid}{lastresult}{timestamp} + $handle{$uuid}{timeout}) < time()) or $state{$uuid}{lastresult}{value} ne "$result"))
@ -274,21 +264,17 @@ while(1)
} }
} }
} }
} }
#print Dumper(\%state); #print Dumper(\%state);
} }
# If a thread has something reported via Log Queue, print it out if verbose is activated # If a thread has something reported via Log Queue, print it out if verbose is activated
while($log_queue->pending) while($log_queue->pending)
{ {
Log 2, $log_queue->dequeue; Log 2, $log_queue->dequeue;
} }
# If a INET socket has anything to report # If a INET socket has anything to report
if(@new_handles = $listener->can_read(1)) if(@new_handles = $listener->can_read(1))
{ {
@ -299,9 +285,9 @@ while(1)
if($client == $server) if($client == $server)
{ {
$new_client = $server->accept(); $new_client = $server->accept();
setsockopt($new_client, SOL_SOCKET, SO_KEEPALIVE, 1); # activate keep-alive setsockopt($new_client, SOL_SOCKET, SO_KEEPALIVE, 1); # activate keep-alive
$listener->add($new_client); $listener->add($new_client);
Log 1, "new connection from ".$new_client->peerhost().":".$new_client->peerport(); Log 1, "new connection from ".$new_client->peerhost().":".$new_client->peerport();
} }
@ -309,33 +295,33 @@ while(1)
{ {
$buf = ''; $buf = '';
$buf = <$client>; $buf = <$client>;
# if the message is defined, it is a real message, else the connection is closed (EOF) # if the message is defined, it is a real message, else the connection is closed (EOF)
if($buf) if($buf)
{ {
# replace leading and trailing white spaces # replace leading and trailing white spaces
$buf =~ s/(^\s*|\s*$)//g; $buf =~ s/(^\s*|\s*$)//g;
# if the message is a new command, accept the command and create threads for all rooms to process the command # if the message is a new command, accept the command and create threads for all rooms to process the command
if($buf =~ /^\s*([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}\s*\|\s*\d+\s*$/) if($buf =~ /^\s*([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}\s*\|\s*\d+\s*$/)
{ {
# send the acknowledgment back to the sender # send the acknowledgment back to the sender
$client->send("command accepted\n"); $client->send("command accepted\n");
Log 2, "received new command from ".$client->peerhost().":".$client->peerport()." - $buf"; Log 2, "received new command from ".$client->peerhost().":".$client->peerport()." - $buf";
# Split the message into bluetooth address and the timeout value # Split the message into bluetooth address and the timeout value
# (timeout is ignored within the collectord, as it is given by configuration) # (timeout is ignored within the collectord, as it is given by configuration)
($address, $timeout) = split("\\|", $buf); ($address, $timeout) = split("\\|", $buf);
# remove any containing white spaces # remove any containing white spaces
$address =~ s/\s*//g; $address =~ s/\s*//g;
$timeout =~ s/\s*//g; $timeout =~ s/\s*//g;
# if the client has already a request running, stop at first the old request # if the client has already a request running, stop at first the old request
if(defined($socket_to_handle{$client})) if(defined($socket_to_handle{$client}))
{ {
my $uuid = $socket_to_handle{$client}; my $uuid = $socket_to_handle{$client};
# get all threads for this socket and send them a termination signal # get all threads for this socket and send them a termination signal
foreach my $room (keys %{$handle{$uuid}{threads}}) foreach my $room (keys %{$handle{$uuid}{threads}})
{ {
@ -344,7 +330,7 @@ while(1)
$state{$uuid}{rooms}{$room}{state} = "" if(exists($state{$uuid}{rooms}{$room})); $state{$uuid}{rooms}{$room}{state} = "" if(exists($state{$uuid}{rooms}{$room}));
delete($state{$uuid}{rooms}{$room}{data}); delete($state{$uuid}{rooms}{$room}{data});
} }
$handle{$uuid}{timeout} = $timeout; $handle{$uuid}{timeout} = $timeout;
$state{$uuid}{lastresult}{timestamp} = 0; $state{$uuid}{lastresult}{timestamp} = 0;
} }
@ -356,27 +342,27 @@ while(1)
$socket_to_handle{$client} = generateUUID(); $socket_to_handle{$client} = generateUUID();
Log 2, "generating new UUID for client ".$client->peerhost()." - ".$socket_to_handle{$client}; Log 2, "generating new UUID for client ".$client->peerhost()." - ".$socket_to_handle{$client};
} }
my $uuid = $socket_to_handle{$client}; my $uuid = $socket_to_handle{$client};
$handle{$uuid}{address} = $address; $handle{$uuid}{address} = $address;
$handle{$uuid}{client} = $client; $handle{$uuid}{client} = $client;
$handle{$uuid}{timeout} = $timeout; $handle{$uuid}{timeout} = $timeout;
$state{$uuid}{lastresult}{value} = "absence"; $state{$uuid}{lastresult}{value} = "absence";
$state{$uuid}{lastresult}{timestamp} = 0; $state{$uuid}{lastresult}{timestamp} = 0;
# create a new reqester thread for each configured room to perform the query # create a new reqester thread for each configured room to perform the query
while (my ($room, $value) = each %config) while (my ($room, $value) = each %config)
{ {
$thread_counter++; $thread_counter++;
$queues{$thread_counter} = Thread::Queue->new(); $queues{$thread_counter} = Thread::Queue->new();
my $new_thread = threads->new(\&doQuery, ($value, $room, $address, $uuid)); my $new_thread = threads->new(\&doQuery, ($value, $room, $address, $uuid));
Log 1, "created thread ".$new_thread->tid()." for processing device $address in room $room for peer ".$client->peerhost()." (UUID: $uuid)"; Log 1, "created thread ".$new_thread->tid()." for processing device $address in room $room for peer ".$client->peerhost()." (UUID: $uuid)";
# detach from the thread, so the thread starts processing independantly # detach from the thread, so the thread starts processing independantly
$new_thread->detach(); $new_thread->detach();
# save the socket/room relationship to know which thread belongs to which client request (for stop command) # save the socket/room relationship to know which thread belongs to which client request (for stop command)
$handle{$uuid}{threads}{$room} = $new_thread; $handle{$uuid}{threads}{$room} = $new_thread;
$state{$uuid}{rooms}{$room}{state} = ""; $state{$uuid}{rooms}{$room}{state} = "";
@ -386,25 +372,25 @@ while(1)
} }
elsif(lc($buf) =~ /^\s*now\s*$/) # if a now command is received, all threads need to be signaled to send a now command to the presenced server elsif(lc($buf) =~ /^\s*now\s*$/) # if a now command is received, all threads need to be signaled to send a now command to the presenced server
{ {
Log 2, "received now command from client ".$client->peerhost(); Log 2, "received now command from client ".$client->peerhost();
# just to be sure if the client has really a running request # just to be sure if the client has really a running request
if(defined($socket_to_handle{$client})) if(defined($socket_to_handle{$client}))
{ {
my $uuid = $socket_to_handle{$client}; my $uuid = $socket_to_handle{$client};
# get all threads for this socket and send them a now command # get all threads for this socket and send them a now command
foreach my $room (keys %{$handle{$uuid}{threads}}) foreach my $room (keys %{$handle{$uuid}{threads}})
{ {
Log 2, "signalling thread ".$handle{$uuid}{threads}{$room}->tid()." to send \"now\"-request for room $room for client ".$client->peerhost(); Log 2, "signalling thread ".$handle{$uuid}{threads}{$room}->tid()." to send \"now\"-request for room $room for client ".$client->peerhost();
$queues{$handle{$uuid}{threads}{$room}->tid()}->enqueue("now"); $queues{$handle{$uuid}{threads}{$room}->tid()}->enqueue("now");
# delete state and room data to get a fresh state # delete state and room data to get a fresh state
$state{$uuid}{rooms}{$room}{state} = "" if(exists($state{$uuid}{rooms}{$room})); $state{$uuid}{rooms}{$room}{state} = "" if(exists($state{$uuid}{rooms}{$room}));
delete($state{$uuid}{rooms}{$room}{data}); delete($state{$uuid}{rooms}{$room}{data});
} }
delete($state{$uuid}{lastresult}) if(exists($state{$uuid}{lastresult})); delete($state{$uuid}{lastresult}) if(exists($state{$uuid}{lastresult}));
$client->send("command accepted\n"); $client->send("command accepted\n");
} }
@ -416,8 +402,8 @@ while(1)
} }
elsif(lc($buf) =~ /^\s*stop\s*$/) # if a stop command is received, the running request threads must be stopped elsif(lc($buf) =~ /^\s*stop\s*$/) # if a stop command is received, the running request threads must be stopped
{ {
Log 1, "received stop command from client ".$client->peerhost(); Log 1, "received stop command from client ".$client->peerhost();
# just to be sure if the client has really a running request # just to be sure if the client has really a running request
if(stopClientThreads($client)) if(stopClientThreads($client))
{ {
@ -429,18 +415,18 @@ while(1)
$client->send("no command running\n"); $client->send("no command running\n");
} }
} }
elsif(lc($buf) =~ /^\s*ping\s*$/) # elsif(lc($buf) =~ /^\s*ping\s*$/) #
{ {
Log 1, "received ping command from client ".$client->peerhost(); Log 1, "received ping command from client ".$client->peerhost();
$client->send("pong\n"); $client->send("pong\n");
closeClientConnection($client); closeClientConnection($client);
} }
else else
{ # if the message does not match a regular command or a stop signal, just tell the client and make a entry for logging. { # if the message does not match a regular command or a stop signal, just tell the client and make a entry for logging.
$client->send("command rejected\n"); $client->send("command rejected\n");
Log 1, "received invalid command >>$buf<< from client ".$client->peerhost(); Log 1, "received invalid command >>$buf<< from client ".$client->peerhost();
} }
} }
else # if the message is not defined (EOF) the connection was closed. Now let's clean up else # if the message is not defined (EOF) the connection was closed. Now let's clean up
@ -455,7 +441,7 @@ while(1)
if(defined($sig_received)) if(defined($sig_received))
{ {
Log 1, "Caught $sig_received exiting"; Log 1, "Caught $sig_received exiting";
unlink($opt_P); unlink($opt_P);
Log 1, "removed PID-File $opt_P"; Log 1, "removed PID-File $opt_P";
Log 1, "server shutdown"; Log 1, "server shutdown";
exit; exit;
@ -471,11 +457,11 @@ Log 2, "leaving main loop";
######################################################################################################################## ########################################################################################################################
# to fork the process from the terminal # to fork the process from the terminal
sub daemonize sub daemonize
{ {
POSIX::setsid or die "setsid $!"; POSIX::setsid or die "setsid $!";
my $pid = fork(); my $pid = fork();
if($pid < 0) if($pid < 0)
@ -503,7 +489,6 @@ sub daemonize
# the thread subroutine which performs a request for a specific room # the thread subroutine which performs a request for a specific room
sub doQuery($$$) sub doQuery($$$)
{ {
my ($do_config, $do_room, $do_address, $do_uuid) = @_; my ($do_config, $do_room, $do_address, $do_uuid) = @_;
my $return; my $return;
my $socket; my $socket;
@ -513,13 +498,13 @@ sub doQuery($$$)
my @client_handle; my @client_handle;
my $reconnect_count = 0; my $reconnect_count = 0;
my $client_socket = undef; my $client_socket = undef;
my $last_contact = gettimeofday(); my $last_contact = gettimeofday();
my $cmd; my $cmd;
my $previous_state = "absence"; my $previous_state = "absence";
my $current_state = "absence"; my $current_state = "absence";
$client_socket = new IO::Socket::INET ( $client_socket = new IO::Socket::INET (
PeerHost => $values{address}, PeerHost => $values{address},
PeerPort => $values{port}, PeerPort => $values{port},
@ -537,30 +522,30 @@ sub doQuery($$$)
$client_socket->send($do_address."|".$values{absence_timeout}."\n"); $client_socket->send($do_address."|".$values{absence_timeout}."\n");
} }
else else
{ {
$selector->remove($client_socket); $selector->remove($client_socket);
$client_socket = undef; $client_socket = undef;
} }
# thread main loop # thread main loop
THREADLOOP: while($run) THREADLOOP: while($run)
{ {
if(defined($client_socket) and not $last_contact > (gettimeofday() - ($current_state eq "absence" ? $values{absence_timeout} : $values{presence_timeout}) - 60)) if(defined($client_socket) and not $last_contact > (gettimeofday() - ($current_state eq "absence" ? $values{absence_timeout} : $values{presence_timeout}) - 60))
{ {
$log_queue->enqueue(threads->tid()."|$do_room socket to ".$values{address}.":".$values{port}." did not report anything in expected time, resetting socket (last contact: ".strftime("%Y-%m-%d %H:%M:%S", localtime($last_contact)).")"); $log_queue->enqueue(threads->tid()."|$do_room socket to ".$values{address}.":".$values{port}." did not report anything in expected time, resetting socket (last contact: ".strftime("%Y-%m-%d %H:%M:%S", localtime($last_contact)).")");
$selector->remove($client_socket); $selector->remove($client_socket);
$client_socket->shutdown(2); $client_socket->shutdown(2);
close($client_socket); close($client_socket);
$client_socket = undef; $client_socket = undef;
} }
if(exists($queues{threads->tid()}) and $queues{threads->tid()}->pending) if(exists($queues{threads->tid()}) and $queues{threads->tid()}->pending)
{ {
$cmd = $queues{threads->tid()}->dequeue; $cmd = $queues{threads->tid()}->dequeue;
$log_queue->enqueue(threads->tid()."|received command: $cmd"); $log_queue->enqueue(threads->tid()."|received command: $cmd");
if($cmd eq "now") if($cmd eq "now")
{ {
$log_queue->enqueue(threads->tid()."|sending \"now\" command to ".$values{address}.":".$values{port}); $log_queue->enqueue(threads->tid()."|sending \"now\" command to ".$values{address}.":".$values{port});
@ -580,9 +565,9 @@ sub doQuery($$$)
elsif($cmd =~ /^new\|/) elsif($cmd =~ /^new\|/)
{ {
($cmd, $do_address) = split("\\|", $cmd); ($cmd, $do_address) = split("\\|", $cmd);
$log_queue->enqueue(threads->tid()."|sending new address $do_address to ".$values{address}.":".$values{port}); $log_queue->enqueue(threads->tid()."|sending new address $do_address to ".$values{address}.":".$values{port});
if($current_state eq "present") if($current_state eq "present")
{ {
$client_socket->send($do_address."|".$values{presence_timeout}."\n") if(defined($client_socket)); $client_socket->send($do_address."|".$values{presence_timeout}."\n") if(defined($client_socket));
@ -593,7 +578,7 @@ sub doQuery($$$)
} }
} }
} }
if(not defined($client_socket)) if(not defined($client_socket))
{ {
# if it's the first occurance # if it's the first occurance
@ -601,11 +586,11 @@ sub doQuery($$$)
{ {
# Tell this the client; # Tell this the client;
$status_queue->enqueue("$do_uuid;$do_room;socket_closed"); $status_queue->enqueue("$do_uuid;$do_room;socket_closed");
# create a log message # create a log message
$log_queue->enqueue(threads->tid()."|$do_room socket to ".$values{address}.":".$values{port}." for device $do_address closed. Trying to reconnect..."); $log_queue->enqueue(threads->tid()."|$do_room socket to ".$values{address}.":".$values{port}." for device $do_address closed. Trying to reconnect...");
} }
# now try to re-establish the connection # now try to re-establish the connection
$client_socket = new IO::Socket::INET ( $client_socket = new IO::Socket::INET (
PeerHost => $values{address}, PeerHost => $values{address},
@ -615,19 +600,19 @@ sub doQuery($$$)
KeepAlive => 1, KeepAlive => 1,
Blocking => 1 Blocking => 1
) or ( $reconnect_count++ ); ) or ( $reconnect_count++ );
if(defined($client_socket)) if(defined($client_socket))
{ {
# give a success message # give a success message
$log_queue->enqueue(threads->tid()."|$do_room reconnected to ".$values{address}.":".$values{port}." after $reconnect_count tries for device $do_address (UUID: $do_uuid)"); $log_queue->enqueue(threads->tid()."|$do_room reconnected to ".$values{address}.":".$values{port}." after $reconnect_count tries for device $do_address (UUID: $do_uuid)");
$status_queue->enqueue("$do_uuid;$do_room;socket_reconnected"); $status_queue->enqueue("$do_uuid;$do_room;socket_reconnected");
# reset the reconnect counter # reset the reconnect counter
$reconnect_count = 0; $reconnect_count = 0;
# set the last contact date to now # set the last contact date to now
$last_contact = gettimeofday(); $last_contact = gettimeofday();
# add the new established socket to the IO selector for incoming data monitoring. # add the new established socket to the IO selector for incoming data monitoring.
$selector->add($client_socket); $selector->add($client_socket);
# send the given address to the presence daemon # send the given address to the presence daemon
@ -638,27 +623,26 @@ sub doQuery($$$)
sleep(9); sleep(9);
} }
} }
# if the socket has a message available # if the socket has a message available
if(@client_handle = $selector->can_read(1)) if(@client_handle = $selector->can_read(1))
{ {
# get all socket handles which has a message available # get all socket handles which has a message available
foreach my $local_client (@client_handle) foreach my $local_client (@client_handle)
{ {
# get the message from the socket handle # get the message from the socket handle
$return = <$local_client>; $return = <$local_client>;
# if the message is defined (not EOF) handle the message... # if the message is defined (not EOF) handle the message...
if($return) if($return)
{ {
# set the last contact date # set the last contact date
$last_contact = gettimeofday(); $last_contact = gettimeofday();
# remove trailing whitespaces and newlines # remove trailing whitespaces and newlines
chomp($return); chomp($return);
# if the message is "command accepted" # if the message is "command accepted"
if($return =~ /command accepted/) if($return =~ /command accepted/)
{ {
@ -673,37 +657,37 @@ sub doQuery($$$)
{ {
# put the message to the status queue with uuid for identification and the room name # put the message to the status queue with uuid for identification and the room name
$status_queue->enqueue("$do_uuid;$do_room;".$return); $status_queue->enqueue("$do_uuid;$do_room;".$return);
# if the state changes from present to absence # if the state changes from present to absence
if(defined($previous_state) and $previous_state eq "present" and lc($return) =~ /^absence/) if(defined($previous_state) and $previous_state eq "present" and lc($return) =~ /^absence/)
{ {
# log the timout change to the log queue # log the timout change to the log queue
$log_queue->enqueue(threads->tid()."|$do_room changing to absence timeout (".$values{absence_timeout}.") for device $do_address"); $log_queue->enqueue(threads->tid()."|$do_room changing to absence timeout (".$values{absence_timeout}.") for device $do_address");
$current_state = "absence"; $current_state = "absence";
# send the new command with the configured absence timeout # send the new command with the configured absence timeout
$local_client->send($do_address."|".$values{absence_timeout}."\n"); $local_client->send($do_address."|".$values{absence_timeout}."\n");
} }
elsif(defined($previous_state) and $previous_state eq "absence" and lc($return) =~ /^present/) elsif(defined($previous_state) and $previous_state eq "absence" and lc($return) =~ /^present/)
{ {
$log_queue->enqueue(threads->tid()."|$do_room changing to presence timeout (".$values{presence_timeout}.") for device $do_address"); $log_queue->enqueue(threads->tid()."|$do_room changing to presence timeout (".$values{presence_timeout}.") for device $do_address");
$current_state = "present"; $current_state = "present";
# if the state changes from absence to present, set the presence timeout # if the state changes from absence to present, set the presence timeout
$local_client->send($do_address."|".$values{presence_timeout}."\n"); $local_client->send($do_address."|".$values{presence_timeout}."\n");
} }
# set the previous state to the current state # set the previous state to the current state
($previous_state, undef) = split(";", lc($return)); ($previous_state, undef) = split(";", lc($return));
} }
} }
else # the socket is EOF which means the connection was closed else # the socket is EOF which means the connection was closed
{ {
$selector->remove($local_client); $selector->remove($local_client);
$local_client->shutdown(2); $local_client->shutdown(2);
close($local_client); close($local_client);
$client_socket = undef; $client_socket = undef;
@ -715,11 +699,8 @@ sub doQuery($$$)
$log_queue->enqueue(threads->tid()."|exiting thread"); $log_queue->enqueue(threads->tid()."|exiting thread");
} }
sub readConfig sub readConfig
{ {
my ($ini) = @_; my ($ini) = @_;
my $section; my $section;
@ -733,73 +714,76 @@ sub readConfig
%config = (); %config = ();
open (INI, "$ini") or (print STDERR timestamp()."Can't open $ini: $!\n" and exit(1)); open (INI, "$ini") or (print STDERR timestamp()."Can't open $ini: $!\n" and exit(1));
while (<INI>) {
chomp; while (<INI>)
if (/^\s*?\[([^\]\n\r]+?)\]/) { {
$section = $1; chomp;
} if (/^\s*?\[([^\]\n\r]+?)\]/)
if (/^\s*(\w+?)=(.+?)\s*(#.*)?$/ and defined($section)) { {
$keyword = $1; $section = $1;
$value = $2 ;
# put them into hash
$config{$section}{$keyword} = $value;
}
} }
if (/^\s*(\w+?)=(.+?)\s*(#.*)?$/ and defined($section))
{
$keyword = $1;
$value = $2 ;
# put them into hash
$config{$section}{$keyword} = $value;
}
}
close (INI); close (INI);
# validating config # validating config
foreach my $room (keys %config) foreach my $room (keys %config)
{ {
if(not exists($config{$room}{address})) if(not exists($config{$room}{address}))
{ {
Log 0, "room $room has no value for address configured"; Log 0, "room $room has no value for address configured";
$errorcount++; $errorcount++;
} }
else else
{ {
if(not $config{$room}{address} =~ /^[a-zA-Z0-9.-]+$/) if(not $config{$room}{address} =~ /^[a-zA-Z0-9.-]+$/)
{ {
Log 0, "no valid address for room $room found: ".$config{$room}{address}; Log 0, "no valid address for room $room found: ".$config{$room}{address};
$errorcount++; $errorcount++;
} }
} }
if(not exists($config{$room}{port})) if(not exists($config{$room}{port}))
{ {
Log 0, "room >>$room<< has no value for >>port<< configured"; Log 0, "room >>$room<< has no value for >>port<< configured";
$errorcount++; $errorcount++;
} }
else else
{ {
if(not $config{$room}{port} =~ /^\d+$/) if(not $config{$room}{port} =~ /^\d+$/)
{ {
Log 0, "value >>port<< for room >>$room<< is not a number: ".$config{$room}{port}; Log 0, "value >>port<< for room >>$room<< is not a number: ".$config{$room}{port};
$errorcount++; $errorcount++;
} }
} }
if(not exists($config{$room}{absence_timeout})) if(not exists($config{$room}{absence_timeout}))
{ {
Log 0, "room >>$room<< has no value for >>absence_timeout<< configured"; Log 0, "room >>$room<< has no value for >>absence_timeout<< configured";
$errorcount++; $errorcount++;
} }
else else
{ {
if(not $config{$room}{absence_timeout} =~ /^\d+$/) if(not $config{$room}{absence_timeout} =~ /^\d+$/)
{ {
Log 0, "value >>absence_timeout<< value for room >>$room<< is not a number: ".$config{$room}{absence_timeout}; Log 0, "value >>absence_timeout<< value for room >>$room<< is not a number: ".$config{$room}{absence_timeout};
$errorcount++; $errorcount++;
} }
} }
if(not exists($config{$room}{presence_timeout})) if(not exists($config{$room}{presence_timeout}))
{ {
Log 0, "room >>$room<< has no value for >>presence_timeout<< configured"; Log 0, "room >>$room<< has no value for >>presence_timeout<< configured";
$errorcount++; $errorcount++;
} }
else else
{ {
@ -809,7 +793,7 @@ sub readConfig
$errorcount++; $errorcount++;
} }
} }
foreach my $param (keys %{$config{$room}}) foreach my $param (keys %{$config{$room}})
{ {
if(not $param =~ /(address|port|absence_timeout|presence_timeout)/) if(not $param =~ /(address|port|absence_timeout|presence_timeout)/)
@ -822,7 +806,7 @@ sub readConfig
} }
if($errorcount) if($errorcount)
{ {
print STDERR timestamp()."found $errorcount config errors. exiting....\n"; print STDERR timestamp()."found $errorcount config errors. exiting....\n";
exit 2; exit 2;
} }
@ -832,10 +816,8 @@ sub readConfig
} }
} }
sub aggregateRooms sub aggregateRooms
{ {
my ($hash) = @_; my ($hash) = @_;
my $previous = "absence"; my $previous = "absence";
@ -845,16 +827,16 @@ sub aggregateRooms
my $key; my $key;
my $first_key; my $first_key;
# get all present rooms # get all present rooms
foreach $key (keys %$hash) foreach $key (keys %$hash)
{ {
my $room_hash = $hash->{$key}; my $room_hash = $hash->{$key};
if(defined($room_hash->{state}) and $room_hash->{state} ne "") if(defined($room_hash->{state}) and $room_hash->{state} ne "")
{ {
my ($value, $data) = split(";", $hash->{$key}); my ($value, $data) = split(";", $hash->{$key});
if($room_hash->{state} eq "present") if($room_hash->{state} eq "present")
{ {
push @rooms, $key; push @rooms, $key;
@ -862,31 +844,30 @@ sub aggregateRooms
} }
else else
{ {
# if one room has no result return undef # if one room has no result return undef
return undef; return undef;
} }
} }
# if multiple rooms are present, try selection by highest RSSI # if multiple rooms are present, try selection by highest RSSI
if(@rooms > 0) if(@rooms > 0)
{ {
my $rssi_addon_data_key = "rssi"; my $rssi_addon_data_key = "rssi";
my $rssi_available = 1; my $rssi_available = 1;
my $highest_value; my $highest_value;
my $highest_key; my $highest_key;
foreach $key (@rooms) foreach $key (@rooms)
{ {
my $data = $hash->{$key}{data}; my $data = $hash->{$key}{data};
if(defined($data)) if(defined($data))
{ {
my ($a,$h) = parseParams($data,';'); my ($a,$h) = parseParams($data,';');
if(@{$a} == 1 and keys(%{$h}) == 0) # old presenced device name => convert to new style if(@{$a} == 1 and keys(%{$h}) == 0) # old presenced device name => convert to new style
{ {
$hash->{$key}{data} = "device_name='".$hash->{$key}{data}."'"; $hash->{$key}{data} = "device_name='".$hash->{$key}{data}."'";
$rssi_available = 0; $rssi_available = 0;
} }
elsif(@{$a} == 0 and keys(%{$h}) > 0) # new addon data style elsif(@{$a} == 0 and keys(%{$h}) > 0) # new addon data style
@ -913,7 +894,7 @@ sub aggregateRooms
} }
} }
} }
if($rssi_available and defined($highest_key)) if($rssi_available and defined($highest_key))
{ {
Log 2, "successful RSSI comparisation (highest $rssi_addon_data_key value $highest_value found in room $highest_key" if(@rooms > 1); Log 2, "successful RSSI comparisation (highest $rssi_addon_data_key value $highest_value found in room $highest_key" if(@rooms > 1);
@ -923,12 +904,11 @@ sub aggregateRooms
if(@rooms > 0) if(@rooms > 0)
{ {
my $rssi_data = join(";", map("rssi_".$_."='".$rssi_results{$_}."'", map {s/\s+/_/rg } keys %rssi_results)); return "present".
my $ret = "present". ";rooms='".join(",",sort @rooms)."'".
(defined($hroom) ? ";room='".$hroom."'" : ""). (defined($hroom) ? ";room='".$hroom."'" : "").
";rooms='".join(",",sort @rooms)."'". (%rssi_results ? ";".join(";", map { "rssi_".($_ =~ s/\s+/_/gr)."='".$rssi_results{$_}."'" } keys %rssi_results) : "").
(defined($hroom) ? ";".$hash->{$hroom}{data} : (defined($hash->{$rooms[0]}{data}) ? ";".$hash->{$rooms[0]}{data} : "")). (defined($hroom) ? ";".$hash->{$hroom}{data} : (defined($hash->{$rooms[0]}{data}) ? ";".$hash->{$rooms[0]}{data} : ""));
(defined($rssi_data) ? ";".$rssi_data : "");
} }
else else
{ {
@ -965,7 +945,7 @@ sub Log($$)
{ {
($thread, $message) = split("\\|", $message); ($thread, $message) = split("\\|", $message);
} }
if($loglevel <= $opt_v) if($loglevel <= $opt_v)
{ {
if($opt_l) if($opt_l)
@ -1055,12 +1035,12 @@ sub parseParams($;$)
sub closeClientConnection($) sub closeClientConnection($)
{ {
my ($client) = @_; my ($client) = @_;
# make a log entry and remove the socket from the socket selector # make a log entry and remove the socket from the socket selector
Log 1, "closed connection from ".$client->peerhost(); Log 1, "closed connection from ".$client->peerhost();
$listener->remove($client); $listener->remove($client);
# if there is a running command, stop it first and clean up # if there is a running command, stop it first and clean up
stopClientThreads($client); stopClientThreads($client);
# now close the socket, that's it # now close the socket, that's it
@ -1070,24 +1050,24 @@ sub closeClientConnection($)
sub stopClientThreads($) sub stopClientThreads($)
{ {
my ($client) = @_; my ($client) = @_;
# if there is a running command, stop it first and clean up (same as stop command, see above) # if there is a running command, stop it first and clean up (same as stop command, see above)
if(defined($socket_to_handle{$client})) if(defined($socket_to_handle{$client}))
{ {
my $uuid = $socket_to_handle{$client}; my $uuid = $socket_to_handle{$client};
# get all threads for this socket and send them a termination signal # get all threads for this socket and send them a termination signal
foreach my $room (keys %{$handle{$uuid}{threads}}) foreach my $room (keys %{$handle{$uuid}{threads}})
{ {
Log 2, "killing thread ".$handle{$uuid}{threads}{$room}->tid()." for room $room for client ".$client->peerhost(); Log 2, "killing thread ".$handle{$uuid}{threads}{$room}->tid()." for room $room for client ".$client->peerhost();
$queues{$handle{$uuid}{threads}{$room}->tid()}->enqueue("stop"); $queues{$handle{$uuid}{threads}{$room}->tid()}->enqueue("stop");
delete($handle{$uuid}{threads}{$room}); delete($handle{$uuid}{threads}{$room});
} }
# when all threads are signaled, delete all relationship entry for this client # when all threads are signaled, delete all relationship entry for this client
delete($handle{$uuid}); delete($handle{$uuid});
delete($socket_to_handle{$client}); delete($socket_to_handle{$client});
return 1; return 1;
} }
else else