Perl Socket Connection Check - perl

I've been trying to debug this perl issue for awhile but had made no head way. what I'm trying to do is determain if the connection is a socks4/5 connection.
# ./pctest.pl
Name "main::junk" used only once: possible typo at ./pctest.pl line 60.
Name "main::empty" used only once: possible typo at ./pctest.pl line 60.
IO::Socket::INET: Bad hostname 'C1(X' ...propagated at ./pctest.pl line 52.
I've also had this error (before i added or die #$; at the end):
Can't use an undefined value as a symbol reference at ./pctest.pl line 56.
.
...
$look = IO::Socket::INET->new( PeerAddr => $_, Proto => 'tcp', Timeout => 5 ) or die #$;
$sock4 = pack( "CCS", 4, 1, 80 );
print $look $sock4;
read( $look, $recv, 10 );
( $empty, $granted, $junk ) = unpack( "C C C6", $recv );
if( $granted == 0x5A )
{
print " Yes\n";
}
else
{
print " No\n";
}
...

There's a typo. #$ should really be $#.
To get rid of the "possible typo" messages and since $empty and $junk seem to be unused in your code, write:
my #result = unpack("C C C6", $recv);
if ($result[1] == 0x5A) {
# ...
}

Just a side note : I think you are thinking of $#, instead of #$. You need to enclose the code in an
eval { ... };
construction. See:
my $look;
eval { $look = IO::Socket::INET->new( PeerAddr => $_, Proto => 'tcp', Timeout => 5 ) };
if ($#) {
do_something_with($#);
}
Granted, that doesn't answer the original question :)

The error message means that your parameter value for PeerAddr in the IO::Socket::INET->new call is invalid.
The constructor expects the PeerAddr value to be a hostname or an IP address (nnn.nnn.nnn.nnn). Check the contents of $_ and I bet you'll find something different.

Related

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

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);

Having trouble with hashes; first time Perl questions

I'm really sorry if this question is too vague; I'll do my best to try and summarize my problem. It's my first time messing with Perl and I think I'm close to getting it.
I have a hash that stores information on calls as they are received from Asterisk.
Each call should have an entry in the hash, with the key being the unique ID (I know this might be bad practice, but the key will be destroyed at the end of the script, so I'm not worried about duplication).
I need to continually append new data to the hash element as I get it from Asterisk, and then at certain times print the results to a TCP socket.
Here's what I've got. My problem is that I can't seem to append the new data to the same hash key.
Please excuse my amateurism; any help on formatting/best practice/anything is appreciated!
use Asterisk::AMI;
use IO::Socket;
use strict;
use warnings;
use Data::Dumper;
my %call;
my $sock = new IO::Socket::INET(
PeerAddr => '127.0.0.1',
PeerPort => '1234',
Proto => 'tcp',
);
die "Could not create socket: $!\n" unless $sock;
my $astman = Asterisk::AMI->new(
PeerAddr => '127.0.0.1',
PeerPort => '5038',
Username => 'user',
Secret => 'secret',
Events => 'on',
Handlers => {
#default => \&eventhandler,
Dial => \&ringcheck,
Bridge => \&bridgecheck,
Newchannel => \&newchannel
}
);
die "Unable to connect to asterisk" unless ($astman);
# Default event handler
sub eventhandler {
my ($ami, $event) = #_;
print 'Got Event: ', $event->{'Event'}, "\r\n";
}
sub newchannel {
my ($ami, $event) = #_;
if ($event->{'Context'} eq "from-trunk") {
$call = $event->{'Uniqueid'} => {
caller_name => $event->{'CallerIDName'},
caller_number => $event->{'CallerIDNum'},
dnis => $event->{'Exten'}
};
}
}
sub ringcheck {
my ($ami, $event) = #_;
if ($event->{'SubEvent'} eq "Begin") {
$call = $event->{'UniqueID'} => {
system_extension => $event->{'Dialstring'},
dest_uniqueid => $event->{'DestUniqueID'}
};
print $sock "R|", $call{ $event->{'UniqueID'} }{'caller_name'}, "|",
$call{ $event->{'UniqueID'} }{'caller_number'}, "|",
$call{ $event->{'UniqueID'} }{'system_extension'}, "||",
$call{ $event->{'UniqueID'} }{'dnis'}, "\r\n";
}
}
sub bridgecheck {
my ($ami, $event) = #_;
if ($event->{'Bridgestate'} eq "Link") {
# Call has started
print $sock "A|", $call{ $event->{'UniqueID'} }{'caller_name'}, "|",
$call{ $event->{'UniqueID'} }{'caller_number'}, "|",
$call{ $event->{'UniqueID'} }{'system_extension'}, "||",
$call{ $event->{'UniqueID'} }{'dnis'}, "\r\n";
}
elsif ($event->{'Bridgestate'} eq "Unlink") {
# Call has ended
}
}
EV::loop
To be clear, the question is how should I be appending the new data, in the ringcheck subroutine for instance, to the %call hash created in the newchannel subroutine?
Since you don't have $call declared you must have had an error message from use strict. It would have helped a lot if you told us that.
Please use minimal indenting: four spaces or less is usual, and I use two. Large indents make the code difficult to follow
Don't terminate a line of output with "\r\n", even on Windows. Perl handles all that, and you should just print "\n" for a newline on any platform
The hash %call is a completely separate variable from the scalar $call, so assigning to $call won't affect your hash at all. If strict was in place you would have seen an error because $call hasn't been defined
To assign to a hash element, use $hash{$key}. Think of it like an array element, but instead of integers, hash elements are indexed with strings. If you want to use a constant as a hash key then you may omit the quotation marks, so $call{'caller_name'} is the same as $call{caller_name}
Looking just at ringcheck for now, it makes your code much more brief and easier to follow if you copy out the value of $event->{UniqueID} into a scalar variable instead of using the same hash element everywhere you need it. You can do the same thing with hash reference $call{$unique_id}
I have changed your code to something that may work, or at least will help you on your way. I have used printf to separate the format from the data and make it more readable.
sub ringcheck {
my ($ami, $event) = #_;
if ($event->{SubEvent} eq 'Begin') {
my $unique_id = $event->{UniqueID};
my $this_call = $call{$unique_id};
$this_call->{system_extension} = $event->{Dialstring};
$this_call->{dest_uniqueid} = $event->{DestUniqueID};
printf $sock "R|%s|%s|%s||%s\n",
$this_call->{caller_name},
$this_call->{caller_number},
$this_call->{system_extension},
$this_call->{dnis};
}
}
You're using the wrong operator for assignment. => is a synonym for ,, with the additional effect of quoting its left-hand operand (unless it's a variable.)
I don't know anything about Asterisk, but you probably want:
$event->{'UniqueID'} = {
system_extension => $event->{'Dialstring'},
dest_uniqueid => $event->{'DestUniqueID'}
};
I'm not sure what you're trying to do with $call, though.

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).

Print fails when using chomp()

So I have this problem while looping through a socket with a while loop.
When I use this, it totally works fine but I have newlines on every $message, which I don't want.
my $socket = new IO::Socket::INET (
LocalHost => "127.0.0.1",
LocalPort => "12345",
Proto => 'tcp',
Listen => 1,
Reuse => 1
);
my $client = $socket->accept();
while(<$client>) {
my $message = $_;
print $message;
}
But when I add the chomp the loop only finished when I disconnect the client (which I understand why).
My guess is that chomp removes the newline from the $_ variable and thus the loop will not work anymore.
my $socket = new IO::Socket::INET (
LocalHost => "127.0.0.1",
LocalPort => "12345",
Proto => 'tcp',
Listen => 1,
Reuse => 1
);
my $client = $socket->accept();
while(<$client>) {
my $message = $_;
chomp($message);
print $message;
}
So my question is: How can I loop through the socket (newline terminated) without having the newlines in the messages?
Thanks a bunch!
The chomp is made on a copy of $_, so it should not affect the socket handle at all. More likely, the removal of the newline is making your print statement wait in the buffer, and execute once the script is terminated.
In other words: It's not an error, just a delay.
Try using autoflush to execute the print immediately.
$| = 1;