package POEDaemon::TCPClient::SHCP; use strict; use warnings FATAL => 'all'; no warnings 'redefine'; use POE; use POEDaemon; sub states { return $_[0], [qw( tcpclient_onconnect tcpclient_ondisconnect tcpclient_input tcpclient_output tcpclient_idle tcpclient_graceful_disconnect )]; } sub tcpclient_onconnect { my ($kernel, $heap, $wheel_id) = @_[KERNEL, HEAP, ARG0]; my $client = $heap->{tcpclient}->{connections}->{$wheel_id}; return unless $client; return unless $client->{wheel}; my $output = sprintf "%s ready", POECLIENT_CMD_PREFIX; $kernel->yield(tcpclient_output => { wheel_id => $wheel_id, output => $output, }); } sub tcpclient_ondisconnect { my $heap = $_[HEAP]; $heap->{shcp}->{powercontrol} = {}; } sub tcpclient_input { my ($kernel, $session, $heap, $input, $wheel_id) = @_[KERNEL, SESSION, HEAP, ARG0, ARG1]; my $client = $heap->{tcpclient}->{connections}->{$wheel_id}; return unless $client; my $sock_wheel_id = $client->{sock_wheel_id}; my $ssl_filter = $client->{ssl_filter}; $client->{last_input_time} = time_hires; if (!$client->{ssl_ok} && $ssl_filter) { unless ($ssl_filter->handshakeDone) { log_enabled && logline "[tcpclient #%s conn #%s] ssl handshake not done yet", $sock_wheel_id, $wheel_id; return; } my $ssl_cipher = $ssl_filter->getCipher; if ($ssl_cipher =~ /none/i) { log_enabled && logline "[tcpclient #%s conn #%s] ssl server cipher = none", $sock_wheel_id, $wheel_id; delete $heap->{tcpclient}->{connections}->{$wheel_id}; if (cfg->{tcpclient_connected_gpio_pin} && !%{$heap->{tcpclient}->{connections}}) { $kernel->yield(gpiochange_set => { pin => cfg->{tcpclient_connected_gpio_pin}, value => GPIO_LOW }); } return; } log_enabled && logline "[tcpclient #%s conn #%s] ssl server cipher = %s", $sock_wheel_id, $wheel_id, $ssl_cipher || 'n/a'; $client->{cipher} = $ssl_cipher if $ssl_cipher; $client->{ssl_handshake_time} = time_hires; $client->{ssl_ok} = 1; } log_enabled && logline "[tcpclient #%s conn #%s] input = '%s'", $client->{sock_wheel_id}, $wheel_id, $input; return unless $client->{ssl_ok}; my @out; return unless $input =~ s/^\s*poeserver\s*//i; if ($input =~ /^\s*ping(?:\s+([a-z0-9_.-]{1,255}))?\s*$/i) { my $ping_args = $1; if (defined $ping_args) { push @out, sprintf "pong %s", $ping_args; } else { push @out, 'pong'; } } elsif ($input =~ /^\s*loadavg\s*$/i) { $kernel->yield(sysctlget => { sysctl => 'vm.loadavg', source_wheel_id => $wheel_id, source_type => 'poeclient', }); } elsif ($input =~ /^\s*sysuptime\s*$/i) { if (cfg->{syslog_high_priority_debug} && !$client->{syslog_ssl_connection_established}) { $client->{syslog_ssl_connection_established} = 1; syslogline '#4, ssl connection to server fully established', { high_priority => 1 }; } $kernel->yield(sysctlget => { sysctl => 'kern.boottime', source_wheel_id => $wheel_id, source_type => 'poeclient', }); } elsif ($input =~ /^\s*sysversion\s*$/i) { $kernel->yield(sysctlget => { sysctl => 'kern.version', source_wheel_id => $wheel_id, source_type => 'poeclient', }); } elsif ($input =~ /^\s*ntpsyspeer\s*$/i) { if (exists $heap->{statelist}->{ntpdc} && $heap->{statelist}->{ntpdc}) { $kernel->yield(ntpdc => { cmd => 'sysinfo', source_wheel_id => $wheel_id, source_type => 'poeclient', }); } else { log_enabled && logline 'invalid state ntpdc'; } } elsif ($input =~ /^\s*rootfs\s*$/i) { push @out, sprintf "rootfs %s", $heap->{rootfs}; } elsif ($input =~ /^\s*poeinittime\s*$/i) { push @out, sprintf "poeinittime %s", $heap->{poe_init_time} - $^T; } elsif ($input =~ /^\s*sysinittime\s*$/i) { if (exists $heap->{init_sysctls} && exists $heap->{init_sysctls}->{'kern.boottime'} && defined $heap->{init_sysctls}->{'kern.boottime'}) { push @out, sprintf "sysinittime %s", $^T - $heap->{init_sysctls}->{'kern.boottime'}; } } elsif ($input =~ /^\s*rtt\s+(\d{10}\.\d{6})\s*$/i) { push @out, sprintf "rtt %s", $1; } elsif ($input =~ /^\s*ubootversion\s*$/i) { if (exists $heap->{init_kenvs} && exists $heap->{init_kenvs}->{'uboot.ver'} && defined $heap->{init_kenvs}->{'uboot.ver'}) { push @out, sprintf "ubootversion %s", $heap->{init_kenvs}->{'uboot.ver'}; } } elsif ($input =~ /^\s*ubootbootcount\s*$/i) { if (exists $heap->{init_kenvs} && exists $heap->{init_kenvs}->{'uboot.bootcount'} && defined $heap->{init_kenvs}->{'uboot.bootcount'}) { push @out, sprintf "ubootbootcount %s", $heap->{init_kenvs}->{'uboot.bootcount'}; } } elsif ($input =~ /^\s*compilerversion\s*$/i) { if (exists $heap->{init_sysctls} && exists $heap->{init_sysctls}->{'kern.compiler_version'} && defined $heap->{init_sysctls}->{'kern.compiler_version'}) { push @out, sprintf "compilerversion %s", $heap->{init_sysctls}->{'kern.compiler_version'}; } } elsif ($input =~ /^\s*shcppowercontrol\s+([\w=\s]{3,1024})\s*$/i) { my $powercontrol_args = $1; $heap->{shcp}->{powercontrol} = {}; foreach (split /\s+/, $powercontrol_args) { if (/^(.+)=(.+)$/) { my $name = lc $1; my $value = lc $2; $heap->{shcp}->{powercontrol}->{$name} = $value; } } } return unless @out && $client->{wheel}; my $output = join "\n", map { sprintf "%s %s", POECLIENT_CMD_PREFIX, $_ } @out; $kernel->call($session => tcpclient_output => { wheel_id => $wheel_id, output => $output, }); } sub tcpclient_output { my ($kernel, $heap, $args) = @_[KERNEL, HEAP, ARG0]; my $wheel_id = $args->{wheel_id}; my $output = $args->{output}; my $use_flush = $args->{use_flush}; return unless $wheel_id && $output; my $client = $heap->{tcpclient}->{connections}->{$wheel_id}; return unless $client; my $wheel = $client->{wheel}; return unless $wheel; log_enabled && logline "[tcpclient #%s conn #%s]%s output = '%s'", $heap->{tcpclient}->{connections}->{$wheel_id}->{sock_wheel_id}, $wheel_id, ($use_flush ? ' flush' : ''), $output; $client->{last_output_time} = time_hires; $wheel->put($output); $wheel->flush if $use_flush; } sub tcpclient_idle { my ($kernel, $heap, $wheel_id) = @_[KERNEL, HEAP, ARG0]; return unless $heap->{tcpclient}->{connections}->{$wheel_id}; my $output = sprintf "%s idle", POECLIENT_CMD_PREFIX; $kernel->yield(tcpclient_output => { wheel_id => $wheel_id, output => $output, }); } sub tcpclient_graceful_disconnect { my ($kernel, $heap, $wheel_id) = @_[KERNEL, HEAP, ARG0]; my $wheel = $heap->{tcpclient}->{connections}->{$wheel_id}->{wheel}; my $output = sprintf "%s shutdown %s", POECLIENT_CMD_PREFIX, $heap->{shutdown_reason} || 'n/a'; $wheel->event(FlushedEvent => 'tcpclient_shutdown'); $kernel->yield(tcpclient_output => { wheel_id => $wheel_id, output => $output, }); } 1;