Perl script error Can't use an undefined value as a symbol reference at ./sendEvent.pl line 66 - perl

Hello everyone i am new to perl scripting and below is my perl script
#!/usr/bin/perl
#use strict;
use warnings;
use 5.010;
I am getting the error
Can't use an undefined value as a symbol reference at ./sendEvent.pl line 66.
can anyone please tell me what is the issue?

It seems as though your socket isn't connected, as that's where the undefined reference is being generated.
Try ensuring that your socket is opened with the IO::Socket call...
$sock = IO::Socket::INET->new(PeerAddr => "$hostname",
PeerPort => "$port",
Proto => 'tcp')
or die "can't connect to port $port on $hostname: $!";
or somesuch.
See where that gets you. At the very least you'll know whether the socket connects correctly.

Attn: OP
Suggestion: use of hash simplifies typing and make code more readable
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use IO::Socket;
use Getopt::Long qw(GetOptions);
use Data::Dumper;
my %unit;
my #keys = qw(host port source name value part ptype module);
my #threshold = ("1000000");
# Defaults to avoid typing parameters
%unit = (
host => 'igloz118',
port => '2010',
source => 'APG_HEALTH',
name => 'RawValueCount',
value => '1000002',
part => 'APG',
ptype => 'APG-Frontend',
module => 'connecting',
devtype => 'Host',
group => 'group',
dname => '.lss.emc.com'
);
GetOptions(
'host|h=s' => \$unit{host},
'port|p=s' => \$unit{port},
'source|s=s' => \$unit{source},
'name|n=s' => \$unit{name},
'value|v=s' => \$unit{value},
'part|p=s' => \$unit{part},
'ptype|pt=s' => \$unit{ptype},
'module|m=s' => \$unit{module}
) or die "Usage: $0 --n NAME\n";
$unit{device} = $unit{host}.$unit{dname};
say '::: Parameters :::::';
printf "%-8s = %s\n", $_, $unit{$_} for #keys;
say '::::::::::::::::::::';
my $sock = IO::Socket::INET->new(
PeerAddr => $unit{hostname},
PeerPort => $unit{port},
Proto => 'tcp'
) or die "can't connect to port $unit{port} on $unit{host}: $!";;
#keys = qw/group variable value device devtype module part parttype name threshold source/;
for (my $i = 0; $i <=0 ; $i++) {
my($timestamp,$raw);
$timestamp = time;
$unit{threshold} = $threshold[$i];
$unit{variable} = join '.', #unit{qw/source device part name/};
$raw = join "\t", ( '+r', $timestamp, #unit{#keys} );
print "$raw";
print $sock "$raw";
}
close($sock);

Related

perl socket: increment port if in use

I have the following code:
use IO::Socket::INET;
use Sys::Hostname;
use Socket;
my($addr)=inet_ntoa((gethostbyname(hostname))[4]);
my $port_to_use = 7777;
my $socket = new IO::Socket::INET (
LocalHost => $addr,
LocalPort => $port_to_use,
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "cannot create socket $!\n" unless $socket;
my $client_socket = $socket->accept();
if i start this in one screen and start another one in the other screen, i get an error:
cannot create socket Address already in use
instead of dying, i would like to try using different port (increment by 1) until it can find the one to use.
I've try to convert the die line with eval but im not able to catch it
any suggestions?
Use a Loop:
use IO::Socket::INET;
use Sys::Hostname;
use Socket;
my($addr)=inet_ntoa((gethostbyname(hostname))[4]);
my $port_to_use = 7776;
my $fail =1;
my $socket;
while ($fail == 1){
$port_to_use++;
$fail = 0;
warn $port_to_use;
$socket = IO::Socket::INET->new (
LocalHost => $addr,
LocalPort => $port_to_use,
Proto => 'tcp',
Listen => 5,
Reuse => 0
) or $fail =1;
}
warn $socket->accept();
Here is a tidier alternative which actually checks to make sure the failure to bind to a given port was due to the port being in use. It also limits the port range to check. If you use the code in the other answer, and, if for some reason, the machine is not allowing your application to bind to any ports, you are going to get stuck in an infinite loop. It may also cause your application to bind to ports that should otherwise have been left alone etc.
#!/usr/bin/env perl
use strict;
use warnings;
use Carp qw( croak );
use Errno qw( EADDRINUSE );
use IO::Socket::INET;
use Sys::Hostname qw( hostname );
use Socket;
# These can come from a config file or command line
# See also https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Dynamic.2C_private_or_ephemeral_ports
# https://unix.stackexchange.com/a/39784/2371
my #port_range = (0xC000, 0xFFFF);
my $addr = inet_ntoa( (gethostbyname(hostname) )[4]);
my $socket;
TRY_PORT:
for my $port ($port_range[0] .. $port_range[1]) {
warn "Trying port $port\n";
$socket = IO::Socket::INET->new(
LocalHost => $addr,
LocalPort => $port,
Proto => 'tcp',
Listen => 7,
Reuse => 0,
);
if ($socket) {
warn "Bound to port $port\n";
last TRY_PORT;
}
if ( EADDRINUSE != $! ) {
croak "Cannot bind to port '$port': $!";
}
warn "Port in use, trying the next one\n";
}
$socket->accept
or croak "...";
# ...

Can't figure out how to fix this script in perl

I'm running this script in perl and correctly putting in the id and port. however, I keep getting "scalar found where operator expected at line 16 near"'skype://1024,'$ARGV"
#!usr/perl/bin
use LWP::UserAgent;
system("color a");
system("title Skype <<");
system("cls");
if(!$ARGV[0]||!$ARGV[1]) {
print q {
Usage : perl skype.pl [userid] [port=1024,80,433]
};
}
else {
use IO::Socket;
my $sock = new IO::Socket::INET (
PeerAddr => 'skype://'.$ARGV[0],
PeerPort => 'skype://1024,'$ARGV[1],
Proto => 'tcp',
);
die "Video Call Error: $!\n" unless $sock;
print $sock "skype://0x77656263616d5f647269766572\n";
system("start ".$sock);
}
# jvoid(document.write(document.currentUser.id));
You have a typo there:
PeerPort => 'skype://1024,'$ARGV[1],
Should be:
PeerPort => 'skype://1024,'.$ARGV[1],
# ^--- missing period

Scalar value errors (with IO::Socket)

This is my current code:
#!/usr/bin/perl -w
use strict;
require IO::Socket;
while (<>) {
chomp(my $host = $_);
my #header;
print "Connecting to: $host\n";
my $socket = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => 80,
Proto => 'tcp') || print "Could not connect: $!\n";
print "Connected.\n";
print $socket "GET / HTTP/1.0\n\n";
my $i = 0;
while (<$socket>) {
#header[$i] = $_;
$i++;
}
$i = 0;
print "--------------------------------------\n";
while ($i <= 8) {
print "#header[$i++]";
}
print "-------------------------------------\n";
print "Finished $host\n\n";
}
If while going through a list of IP's, and a host is down, instead of continuing onto the next IP, it will give me an error "Can't use string ("1") as a symbol ref while "strict refs" in use".
If I then change #header[$i] = $; to $header[$i] = $; I also get the same error. How can I make this script better.
The problem is in the way you set $socket:
my $socket = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => 80,
Proto => 'tcp') || print "Could not connect: $!\n";
Since you're using the || operator, which has higher precedence than =, this statement is parsed as
my $socket = (new IO::Socket::INET(...) || print ...);
If new IO::Socket::INET returns a false value (as it does if the connection fails), the print will be executed and its return value (which is normally 1) will be assigned to $socket.
When you then try to use $socket as an indirect object in the statement:
print $socket "GET / HTTP/1.0\n\n";
Perl notices that the value 1 is not actually an object reference and throws the error you reported.
If you'd used the low-precedence operator or instead of ||, the value of $socket would've been undef instead of 1, and the error message you'd have received would've been something like Can't use an undefined value as a symbol reference .... Of course, this wouldn't have actually fixed your problem, but at least it might've made it easier to diagnose.
To actually fix the problem, you need to fix your code so that you won't keep executing the rest of the loop body if the connection fails. One way to do that would be like this:
my $socket = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => 80,
Proto => 'tcp');
unless ($socket) {
print "Could not connect: $!\n";
next; # skip the rest of the loop
}
Wouldn't the simple solution be to use the lower precedence version 'or' which has lower precedence than '='?
my $socket = new IO::Socket::INET(
PeerAddr => $host,
PeerPort => 80,
Proto => 'tcp')
or print "Could not connect: $!\n";
In fact, the operators 'or', and 'xor', have the lowest operator precedence (see perlop).

How to verify which flags were read using Getopt::Long in Perl?

myscript.pl
my $R;
my $f1 = "f1.log";
my $f2 = "f2.log";
my $f3 = "f3.log";
sub checkflags {
GetOptions('a=s' => \$f1,
'b=s' => \$f2,
'c=s' => \$f3,
);
open $R, '>', $f1 or die "Cannot open file\n"; # Line a
}
All the flags are optional.
If I call the script as
perl myscript.pl -a=filename
I need to append a .log to the filename before opening it at Line a.
For that I need to know whether GetOptions read something into $f1 or not.
How can this be done?
The simplest solution is to look for /[.]log$/ in $f1 and add it if it isn't present. Unfortunately that means that when the user passes in "foo.log" and wanted it to become "foo.log.log" it won't, but I think we can agree that user is a jerk.
A better option, that will make the jerk happy, is:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
GetOptions(
'a=s' => \my $f1,
'b=s' => \my $f2,
'c=s' => \my $f3,
);
if (defined $f1) {
$f1 .= ".log";
} else {
$f1 = "f1.log";
}
print "$f1\n";
If you want to define all of default names at the top, use a different variable to do that (it is probably better reading code anyway):
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
my $default_f1 = "f1.log";
my $default_f2 = "f2.log";
my $default_f3 = "f3.log";
GetOptions(
'a=s' => \my $f1,
'b=s' => \my $f2,
'c=s' => \my $f3,
);
if (defined $f1) {
$f1 .= ".log";
} else {
$f1 = $default_f1;
}
print "$f1\n";
if (defined $f1) {
# You got a -a option
}
But personally I'd prefer to read the options into a hash and then use exists().
$f1 = "$f1.log" unless $f1 =~ m/\.log$/i;
Appends the log extension if the file name does not already have one. Since the default value ends in log, nothing happens. And it works if the user types the log on the command line.
One way to achieve this is to use Moose and MooseX::Getopt:
package MyApp;
use strict;
use warnings;
use Moose;
with 'MooseX::Getopt';
has f1 => (
is => 'ro', isa => 'Str',
cmd_aliases => 'a',
default => 'f1.log',
predicate => 'has_a',
);
has f2 => (
is => 'ro', isa => 'Str',
cmd_aliases => 'b',
default => 'f2.log',
predicate => 'has_b',
);
has f3 => (
is => 'ro', isa => 'Str',
cmd_aliases => 'c',
default => 'f3.log',
predicate => 'has_c',
);
# this is run immediately after construction
sub BUILD
{
my $this = shift;
print "a was provided\n" if $this->has_a;
print "b was provided\n" if $this->has_b;
print "c was provided\n" if $this->has_c;
}
1;

Perl: How to get IO::Socket::INET timeout after X seconds?

I'm trying to connect to some host, using invalid port, and i want to get timeout after X seconds. How to do that ?
My code:
$sock = new IO::Socket::INET(
PeerAddr => $_[0],
PeerPort => $_[1],
Proto => 'tcp',
Timeout => 2
);
If you check the code you'll see (I copied it from my Ubuntu 10.04) :
my $timeout = ${*$sock}{'io_socket_timeout'};
# my $before = time() if $timeout;
undef $#;
if ($sock->connect(pack_sockaddr_in($rport, $raddr))) {
# ${*$sock}{'io_socket_timeout'} = $timeout;
return $sock;
}
return _error($sock, $!, $# || "Timeout")
unless #raddr;
# if ($timeout) {
# my $new_timeout = $timeout - (time() - $before);
# return _error($sock,
# (exists(&Errno::ETIMEDOUT) ? Errno::ETIMEDOUT() : $EINVAL),
# "Timeout") if $new_timeout <= 0;
# ${*$sock}{'io_socket_timeout'} = $new_timeout;
# }
Apparently the timeout stuff is commented out so that expleins why it is ignored.
I found a post dating from 2003 where this was discussed. One suggestion (at the bottom) was to open the socket in an eval block which gets terminated by an alarm signal :
eval {
local $SIG{ALRM} = sub { die 'Timed Out'; };
alarm 3;
my $sock = IO::Socket::INET->new(
PeerAddr => inet_ntoa( gethostbyname($host) ),
PeerPort => 'whois',
Proto => 'tcp',
## timeout => ,
);
$sock->autoflush;
print $sock "$qry\015\012";
undef $/; $data = <$sock>; $/ = "\n";
alarm 0;
};
alarm 0; # race condition protection
return "Error: timeout." if ( $# && $# =~ /Timed Out/ );
return "Error: Eval corrupted: $#" if $#;
Not very elegant, but if it works...
Let's verify with a slow server and impatient client :
# Impatient Client
use IO::Socket::INET;
$sock = new IO::Socket::INET(
PeerAddr => "localhost",
PeerPort => "10007",
Proto => 'tcp',
Timeout => 2,
);
print <$sock>;
close($sock);
# SlowServer
use IO::Socket::INET;
$sock = new IO::Socket::INET(
LocalAddr => "localhost",
LocalPort => "10007",
Proto => 'tcp',
Listen => 1,
Reuse => 1,
);
$newsock = $sock->accept();
sleep 5;
#while (<$newsock>) {
# print $_;
#}
print $newsock "Some Stuff";
close($newsock);
close($sock);
if we run this:
pti#pti-laptop:~/playpen$ perl server.pl&
[1] 9130
pti#pti-laptop:~/playpen$ time perl test.pl
Some Stuff[1]+ Done perl server.pl
real 0m5.039s
user 0m0.050s
sys 0m0.030s
So it ignores the 2 second timeout and runs for the full 5 seconds.
Now the other impatient client :
use IO::Socket::INET;
eval {
local $SIG{ALRM} = sub { die 'Timed Out'; };
alarm 2;
$sock = new IO::Socket::INET(
PeerAddr => "localhost",
PeerPort => "10007",
Proto => 'tcp',
Timeout => 2,
);
print <$sock>;
close($sock);
alarm 0;
};
alarm 0; # race condition protection
print "Error: timeout." if ( $# && $# =~ /Timed Out/ );
print "Error: Eval corrupted: $#" if $#;
~
and running it :
pti#pti-laptop:~/playpen$ perl server.pl&
[1] 9175
pti#pti-laptop:~/playpen$ time perl test2.pl
Error: timeout.Error: Eval corrupted: Timed Out at test2.pl line 3.
real 0m2.040s
user 0m0.020s
sys 0m0.010s
Yep, this timeouts after 2 seconds as expected.
So much easier is to use the
IO::Socket::Timeout
as per below and it works like a charm.
use IO::Socket::Timeout;
my $socket = IO::Socket::INET->new( Timeout => 2 );
IO::Socket::Timeout->enable_timeouts_on($socket);
$socket->read_timeout(0.5); # These will work
$socket->write_timeout(0.5); # These will work