2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-03 16:56:54 +00:00

fixing 2 race conditions where a device is summarized as present instead of absent

git-svn-id: https://svn.fhem.de/fhem/trunk@2726 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
markusbloch 2013-02-14 19:51:11 +00:00
parent 7899db6196
commit 0f1e97717f
2 changed files with 44 additions and 9 deletions

View File

@ -36,7 +36,7 @@ use File::Basename;
use Getopt::Long; use Getopt::Long;
use threads; use threads;
use Thread::Queue; use Thread::Queue;
use Time::HiRes qw(gettimeofday);
use warnings; use warnings;
use strict; use strict;
@ -241,6 +241,11 @@ while(1)
if(not $value =~ /^(absence|present)$/) if(not $value =~ /^(absence|present)$/)
{ {
$handle{$uuid}{client}->send("$value;$room\n"); $handle{$uuid}{client}->send("$value;$room\n");
if($value eq "socket_closed")
{
delete($state{$uuid}{rooms}{$room});
}
} }
else else
{ {
@ -503,11 +508,12 @@ sub doQuery($$$)
my $selector; my $selector;
my @client_handle; my @client_handle;
my $reconnect_count = 0; my $reconnect_count = 0;
my $last_contact = gettimeofday();
my $previous_state = "absence"; my $previous_state = "absence";
my $current_state = "absence";
my $client_socket = new IO::Socket::INET ( my $client_socket = new IO::Socket::INET (
PeerHost => $values{address}, PeerHost => $values{address},
PeerPort => $values{port}, PeerPort => $values{port},
@ -515,7 +521,7 @@ sub doQuery($$$)
Type => SOCK_STREAM, Type => SOCK_STREAM,
KeepAlive => 1, KeepAlive => 1,
Blocking => 1 Blocking => 1
) or ( $log_queue->enqueue("$room: could not create socket to ".$values{address}." - $! - \n") and threads->exit()); ) or ( $log_queue->enqueue("$room: could not create socket to ".$values{address}." - $! - \n"));
# if the thread gets a termination signal, the thread must be shutdown by itself # if the thread gets a termination signal, the thread must be shutdown by itself
local $SIG{TERM} = sub { local $SIG{TERM} = sub {
@ -525,20 +531,36 @@ sub doQuery($$$)
threads->exit(); threads->exit();
}; };
$selector = IO::Select->new($client_socket);
if($client_socket) if($client_socket)
{ {
# send the given address to the presence daemon # send the given address to the presence daemon
$client_socket->send($do_address."|".$values{absence_timeout}."\n"); $client_socket->send($do_address."|".$values{absence_timeout}."\n");
} }
else
# create a socket selector for non-blocking read and disconnect {
$selector = IO::Select->new($client_socket); $selector->remove($client_socket);
$client_socket = undef;
}
# thread main loop # thread main loop
while(1) while(1)
{ {
if(defined($client_socket) and not $last_contact > (gettimeofday() - ($current_state eq "absence" ? $values{absence_timeout} : $values{presence_timeout}) - 60))
{
$log_queue->enqueue("$room: socket to ".$values{address}.":".$values{port}." did not report anything in expected time, resetting socket\n");
$selector->remove($client_socket);
close($client_socket);
$client_socket = undef;
}
if(not defined($client_socket)) if(not defined($client_socket))
{ {
# if it's the first occurance # if it's the first occurance
@ -570,6 +592,9 @@ sub doQuery($$$)
# reset the reconnect counter # reset the reconnect counter
$reconnect_count = 0; $reconnect_count = 0;
# set the last contact date to now
$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
@ -580,18 +605,24 @@ 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
$last_contact = gettimeofday();
# remove trailing whitespaces and newlines # remove trailing whitespaces and newlines
chomp($return); chomp($return);
@ -616,6 +647,8 @@ sub doQuery($$$)
# log the timout change to the log queue # log the timout change to the log queue
$log_queue->enqueue("$room: changing to absence timeout (".$values{absence_timeout}.") for device $do_address\n"); $log_queue->enqueue("$room: changing to absence timeout (".$values{absence_timeout}.") for device $do_address\n");
$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");
} }
@ -623,6 +656,8 @@ sub doQuery($$$)
{ {
$log_queue->enqueue("$room: changing to presence timeout (".$values{presence_timeout}.") for device $do_address\n"); $log_queue->enqueue("$room: changing to presence timeout (".$values{presence_timeout}.") for device $do_address\n");
$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");
} }