C (I think) to Perl Conversion

B

Brad Walton

I'm stuck here... I have a sample script which accomplishes the task I need
done, but it's done in another programing language (of which I have no
understanding). I have researched this for hours and hours, but no luck.

The script I need 'deciphered' to Perl:

----
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <netinet/tcp.h>

int main(int argc, char *argv[] )
{
int sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( sock == -1 )
{
printf( "Socket creation failed" );
exit(-1);
}

struct sockaddr_in rcon_server;
rcon_server.sin_family = AF_INET;
rcon_server.sin_addr.s_addr = inet_addr( "127.0.0.1" );
rcon_server.sin_port = htons( 27015 );

if ( connect( sock, (const struct sockaddr *)&rcon_server,sizeof(
rcon_server ) )!= 0 )
{
printf( "Unable to connect\n");
exit(-1);
}

unsigned char send_buf[4096];
unsigned char *send_ptr = send_buf + sizeof(int);

*(int *)send_ptr = 0x0001; // request id 1
send_ptr += sizeof(int);
*(int *)send_ptr = 0x0003; // command id 3
send_ptr += sizeof(int);

strcpy( (char *)send_ptr, "password" ); // the rcon password
send_ptr += strlen("password") +1; //+1 for null terminator
*(int *)send_ptr = 0; // 2nd string is just null
send_ptr++;
(*(int *)send_buf) = (int)(send_ptr - send_buf - sizeof(int)); //
now setup the size of this packet (NOTE the subtraction of sizeof(int)!!)

printf( "Sending packet (%d bytes)\n", *(int *)(send_buf) );

send( sock, send_buf, *(int *)(send_buf) + sizeof(int), 0 ); // send
the auth request

sleep(1); // ugly hack to give the server time to respond

long readLen;
ioctl( sock, FIONREAD, &readLen );
printf("Got %d bytes from server\n", readLen );

int len = recv( sock, send_buf, readLen, 0);
if ( len < 14 )
{
printf("Didn't read enough data (%i)( TODO: block on
reads)\n", len);
exit(-1);
}

printf( "packet size: %d, request id:%d, command:%d\n",
(int)send_buf[0],(int)send_buf[4],(int)send_buf[8]);

if ( len > 14 ) // a 2nd packet is in the response
{
printf( "packet size: %d, request id:%d, command:%d\n",
(int)send_buf[14],(int)send_buf[18],(int)send_buf[22]);
}

close( sock );
}
----

This is a longshot.. but I don't know what else to do.

Thanks for any help,
Brad
 
U

Uri Guttman

BW> I'm stuck here... I have a sample script which accomplishes the
BW> task I need done, but it's done in another programing language (of
BW> which I have no understanding). I have researched this for hours
BW> and hours, but no luck.

BW> ----

BW> This is a longshot.. but I don't know what else to do.

hire a programmer.

uri
 
G

Gregory Toomey

Brad said:
I'm stuck here... I have a sample script which accomplishes the task I
need done, but it's done in another programing language (of which I have
no understanding). I have researched this for hours and hours, but no
luck.

The script I need 'deciphered' to Perl:

----
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <netinet/tcp.h>

int main(int argc, char *argv[] )
{
int sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( sock == -1 )
{
printf( "Socket creation failed" );
exit(-1);
}

struct sockaddr_in rcon_server;
rcon_server.sin_family = AF_INET;
rcon_server.sin_addr.s_addr = inet_addr( "127.0.0.1" );
rcon_server.sin_port = htons( 27015 );

if ( connect( sock, (const struct sockaddr *)&rcon_server,sizeof(
rcon_server ) )!= 0 )
{
printf( "Unable to connect\n");
exit(-1);
}

unsigned char send_buf[4096];
unsigned char *send_ptr = send_buf + sizeof(int);

*(int *)send_ptr = 0x0001; // request id 1
send_ptr += sizeof(int);
*(int *)send_ptr = 0x0003; // command id 3
send_ptr += sizeof(int);

strcpy( (char *)send_ptr, "password" ); // the rcon password
send_ptr += strlen("password") +1; //+1 for null terminator
*(int *)send_ptr = 0; // 2nd string is just null
send_ptr++;
(*(int *)send_buf) = (int)(send_ptr - send_buf - sizeof(int)); //
now setup the size of this packet (NOTE the subtraction of sizeof(int)!!)

printf( "Sending packet (%d bytes)\n", *(int *)(send_buf) );

send( sock, send_buf, *(int *)(send_buf) + sizeof(int), 0 ); //
send
the auth request

sleep(1); // ugly hack to give the server time to respond

long readLen;
ioctl( sock, FIONREAD, &readLen );
printf("Got %d bytes from server\n", readLen );

int len = recv( sock, send_buf, readLen, 0);
if ( len < 14 )
{
printf("Didn't read enough data (%i)( TODO: block on
reads)\n", len);
exit(-1);
}

printf( "packet size: %d, request id:%d, command:%d\n",
(int)send_buf[0],(int)send_buf[4],(int)send_buf[8]);

if ( len > 14 ) // a 2nd packet is in the response
{
printf( "packet size: %d, request id:%d, command:%d\n",
(int)send_buf[14],(int)send_buf[18],(int)send_buf[22]);
}

close( sock );
}
----

This is a longshot.. but I don't know what else to do.

Thanks for any help,
Brad

Why reinvent the wheel? Compile in C and run.

gtoomey
 
B

Brad Walton

Why reinvent the wheel? Compile in C and run.

Because the other 75% of the program is written in Perl, which I understand.
And, I need to add code to it to make it work in my script. I also have zero
experience with C unfortunately...

Thanks,
Brad
 
S

Sisyphus

Brad said:
I'm stuck here... I have a sample script which accomplishes the task I need
done, but it's done in another programing language (of which I have no
understanding). I have researched this for hours and hours, but no luck.


Looks to me that Inline::C should be able to handle this very simply.
What follows is little other than a copy'n'paste of that C script.
(Beware of line wraps.) I'll leave it to the reader to spot the
differences. You may need to uncomment the 3 Inline Config lines and
specify the same libs that are specified at the C script linking stage.
(If you're able to build the C app from source without having to specify
any libs then you probably don't have to worry about it.)

use warnings;

#use Inline (C => Config =>
# 'LIBS' => [], #eg ['-lm -lmylib']
# );

use Inline C => <<'EOC';
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <netinet/tcp.h>

void do_it()
{
int sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( sock == -1 )
{
croak("Socket creation failed");

}

struct sockaddr_in rcon_server;
rcon_server.sin_family = AF_INET;
rcon_server.sin_addr.s_addr = inet_addr( "127.0.0.1" );
rcon_server.sin_port = htons( 27015 );

if ( connect( sock, (const struct sockaddr *)&rcon_server,sizeof(
rcon_server ) )!= 0 )
{
croak( "Unable to connect");
}

unsigned char send_buf[4096];
unsigned char *send_ptr = send_buf + sizeof(int);

*(int *)send_ptr = 0x0001; // request id 1
send_ptr += sizeof(int);
*(int *)send_ptr = 0x0003; // command id 3
send_ptr += sizeof(int);

strcpy( (char *)send_ptr, "password" ); // the rcon password
send_ptr += strlen("password") +1; //+1 for null terminator
*(int *)send_ptr = 0; // 2nd string is just null
send_ptr++;
(*(int *)send_buf) = (int)(send_ptr - send_buf - sizeof(int)); //
now setup the size of this packet (NOTE the subtraction of sizeof(int)!!)

printf( "Sending packet (%d bytes)\n", *(int *)(send_buf) );

send( sock, send_buf, *(int *)(send_buf) + sizeof(int), 0 ); //
send
the auth request

sleep(1); // ugly hack to give the server time to respond

long readLen;
ioctl( sock, FIONREAD, &readLen );
printf("Got %d bytes from server\n", readLen );

int len = recv( sock, send_buf, readLen, 0);
if ( len < 14 )
{
croak("Didn't read enough data (%i)( TODO: block on
reads)\n", len);
}

printf( "packet size: %d, request id:%d, command:%d\n",
(int)send_buf[0],(int)send_buf[4],(int)send_buf[8]);

if ( len > 14 ) // a 2nd packet is in the response
{
printf( "packet size: %d, request id:%d, command:%d\n",
(int)send_buf[14],(int)send_buf[18],(int)send_buf[22]);
}

close( sock );
}

EOC

do_it();

__END__

Hope it's that simple. I can't see why it shouldn't be.

Things get a little more complex if you start passing values between
perl and the Inline::C function - for help with that aspect first check
out 'perldoc Inline::C-Cookbook'.

The code supplied above has not been tested.

Cheers,
Rob
 
B

Brad Walton

[snip]
Things get a little more complex if you start passing values between
perl and the Inline::C function - for help with that aspect first check
out 'perldoc Inline::C-Cookbook'.

The code supplied above has not been tested.

Cheers,
Rob

Thanks Rob, I'll give it a go. Appreciate the assitance.

Brad
 
P

Peter Scott

I'm stuck here... I have a sample script which accomplishes the task I need
done, but it's done in another programing language (of which I have no
understanding). I have researched this for hours and hours, but no luck.

The script I need 'deciphered' to Perl:

C developers call them 'programs' :)

But you indicated you know Perl already, so you don't need
anyone to turn this program into Perl, you just need an
English translation so you can write the Perl. There are
issues such as byte ordering and length of an int that this
program glosses over.
int main(int argc, char *argv[] )
{
int sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( sock == -1 )
{
printf( "Socket creation failed" );
exit(-1);
}

struct sockaddr_in rcon_server;
rcon_server.sin_family = AF_INET;
rcon_server.sin_addr.s_addr = inet_addr( "127.0.0.1" );
rcon_server.sin_port = htons( 27015 );

if ( connect( sock, (const struct sockaddr *)&rcon_server,sizeof(
rcon_server ) )!= 0 )
{
printf( "Unable to connect\n");
exit(-1);
}

Connect to TCP port 27015 on the local host and die on error.
Suggest: IO::Socket.
unsigned char send_buf[4096];
unsigned char *send_ptr = send_buf + sizeof(int);

*(int *)send_ptr = 0x0001; // request id 1
send_ptr += sizeof(int);
*(int *)send_ptr = 0x0003; // command id 3
send_ptr += sizeof(int);

strcpy( (char *)send_ptr, "password" ); // the rcon password
send_ptr += strlen("password") +1; //+1 for null terminator
*(int *)send_ptr = 0; // 2nd string is just null
send_ptr++;
(*(int *)send_buf) = (int)(send_ptr - send_buf - sizeof(int)); //
now setup the size of this packet (NOTE the subtraction of sizeof(int)!!)

printf( "Sending packet (%d bytes)\n", *(int *)(send_buf) );

send( sock, send_buf, *(int *)(send_buf) + sizeof(int), 0 ); // send
the auth request

Send a packet consisting of a 4-byte (assumption) count of the number
of bytes following, then 4 bytes containing a 1, 4 bytes containing a 3,
and the string "password" (which one assumes may get changed) and a null
byte. perldoc -f pack.
sleep(1); // ugly hack to give the server time to respond

long readLen;
ioctl( sock, FIONREAD, &readLen );
printf("Got %d bytes from server\n", readLen );

Read a response from the socket.
int len = recv( sock, send_buf, readLen, 0);
if ( len < 14 )
{
printf("Didn't read enough data (%i)( TODO: block on
reads)\n", len);
exit(-1);
}

Which must be at least 14 bytes long.
printf( "packet size: %d, request id:%d, command:%d\n",
(int)send_buf[0],(int)send_buf[4],(int)send_buf[8]);

And starts with 3 integers of interest. perldoc -f unpack.
if ( len > 14 ) // a 2nd packet is in the response
{
printf( "packet size: %d, request id:%d, command:%d\n",
(int)send_buf[14],(int)send_buf[18],(int)send_buf[22]);
}

If there are more than 14 bytes in the response, we are also
interested in the three integers starting at byte offset 14.
close( sock );
}

This program is not an interface; it's more of a debugging
print test. Presumably in real life it needs to be turned
into a subroutine that interprets the response.

Lincoln Stein's book on Network Programming with Perl is
invaluable for learning how to do this sort of thing.

Like Uri said, if you want someone to write the Perl for you
as well, there are plenty of people for hire...
 
B

Brad Walton

[snip]
This program is not an interface; it's more of a debugging
print test. Presumably in real life it needs to be turned
into a subroutine that interprets the response.

Lincoln Stein's book on Network Programming with Perl is
invaluable for learning how to do this sort of thing.

Like Uri said, if you want someone to write the Perl for you
as well, there are plenty of people for hire...

Thanks! I don't need anyone to write it for me, I just needed some
understanding (or deciphering) of this script. You have been a great help..
I appreciate it!

Brad
 
K

krakle

Brad Walton said:
I'm stuck here... I have a sample script which accomplishes the task I need
done, but it's done in another programing language (of which I have no
understanding). I have researched this for hours and hours, but no luck.

The script I need 'deciphered' to Perl:

Have you ever thought why someone would take the time to rewrite that
code in Perl for someone they don't know for no reason at all? No one
will. Good luck asking people to do your own work for free...
 
B

Brad Walton

krakle said:
"Brad Walton" <[email protected]> wrote in message

Have you ever thought why someone would take the time to rewrite that
code in Perl for someone they don't know for no reason at all? No one
will. Good luck asking people to do your own work for free...

Hey krakle, if you don't want to help, fine.. cya.
 
B

Brad Walton

Brad Walton said:
[snip]
This program is not an interface; it's more of a debugging
print test. Presumably in real life it needs to be turned
into a subroutine that interprets the response.

Lincoln Stein's book on Network Programming with Perl is
invaluable for learning how to do this sort of thing.

Like Uri said, if you want someone to write the Perl for you
as well, there are plenty of people for hire...

Thanks! I don't need anyone to write it for me, I just needed some
understanding (or deciphering) of this script. You have been a great help..
I appreciate it!

Brad

Ok, this is what I came up with:

----
#!/usr/bin/perl -w
use strict;
use IO::Socket;

# Connect to the rcon server
my $sock = new IO::Socket::INET(PeerAddr => '209.209.44.30', PeerPort =>
'27015', proto => 'tcp',);
if (!$sock) {
die "Unable to connect $@\n";
}

# Pack packs the data according to a format string
# integer,integer,integer,null terminated string,null terminated string

my $login_packet = pack("iiiaa", 18, 1, 3, "password", "");
print "done: $login_packet\n";

# Send on the wire
print $sock $login_packet;

# Dirty hack from Alfred_Reynolds program
# sleep(1);

my $response_packet = <$sock>;

# Unknown response type but it may look something like this:
# protocol not defined in example script
my ($response_size, $response_id, $response) = unpack("iii",
$response_packet);
# more speculation follows:
if ($response_size != 12) {
die "Weird response size ! 12\n";
}

if ($response_id != 1) {
die "Got response for request we did not send\n";
}

if (!$response) {
die "Response == 0 login failed\n";
}

print "All is good!\n";

exit(0);

----

I'm not sure if I translated it properly, as I'm not getting a response from
the other end. Does anyone spot any translation errors?

Thanks for any help, Brad
 
P

Peter Scott

my $response_packet = <$sock>;

You're reading a line back from the socket. The C program showed
no signs of being line oriented. You need sysread() or recv().
 
B

Ben Morrow

Quoth (e-mail address removed):
You're reading a line back from the socket. The C program showed
no signs of being line oriented. You need sysread() or recv().

Or, probably easier, $/ = \NUMBER, which will make <> read in NUMBER-sized
blocks.

Ben
 
S

Sherm Pendley

Santa said:
! is single line comment not requiring an end comment

I don't know what language you're talking about, but it's not C.
Single-line comments in C begin with "//".
There are c manuals online

Perhaps you should read one of them.
The last thing I want to tell you is something odd in c that i really
hate which os an advanced feature called operator overload.

That's C++. Operator overloading is not supported by C.
way that a person can override the + sign and make it into whatever they
want including the - sign. This is meant for those that read a program
and try to take out parts of it and make it not work for them, sort of
like programmer protection.

That's a load of pure BS. That is *NOT* what operator overloading is
meant for. It's meant for situations where you want to take the symantic
meaning that an operator already has, and apply that to object types.

For example, if you have a Matrix class, you can define a "*" operator
that takes two Matrix objects, performs matrix multiplication on them,
and returns the resulting Matrix object.
Hope this helps

FUD never helps. Save the drek for the .advocacy groups.

sherm--
 
J

Jussi Mononen

! is single line comment not requiring an end comment
I don't know what language you're talking about, but it's not C.
Single-line comments in C begin with "//".

Actually it is not, "//" is a C++ single-line comment, but *most*
C-compilers accept it by default.

I would suggest that every Perl programmer would try to learn C, as it is
the language Perl itself is written with :)
 
S

Sherm Pendley

Jussi said:
Actually it is not, "//" is a C++ single-line comment, but *most*
C-compilers accept it by default.

Actually it is. :) Single-line comments are included in the current C99
standard. They weren't part of the C89 standard, but as you say, most
compilers accepted them anyway.
I would suggest that every Perl programmer would try to learn C, as it is
the language Perl itself is written with :)

Indeed. It's also fairly easy to create Perl modules that wrap C libraries.

sherm--
 
J

Jürgen Exner

Sherm said:

Really? I would have thought that Perl was written in English and maybe POD
or EBNF or so.

In case you are talking about perl: It would be a very poor language design
if the language of the compiler/interpreter would have any influence on the
language to be compiled/interpreted.

jue
 
S

Sherm Pendley

Jürgen Exner said:
Really? I would have thought that Perl was written in English and maybe POD
or EBNF or so.

There is no ISO/ANSI/ECMA or other standard for Perl - Perl is as perl
does. In fact, the most concise, accurate definition of the language
Perl is the C code that implements the interpreter perl.

There are, of course, more or less accurate approximations of that
definition in any number of languages - English and other spoken
languages, BNF grammars, POD markup, etc.
In case you are talking about perl: It would be a very poor language design
if the language of the compiler/interpreter would have any influence on the
language to be compiled/interpreted.

It's not so much C's influence on the language design that makes
learning it a good idea. It's the use of C to implement the interpreter,
which is essentially the definition of the language, that does so.

Understanding C makes it possible to dive into the perl source, thereby
gaining a far deeper understanding of just what goes on when your Perl
code runs.

It also makes it possible to extend Perl with XS modules. Much of Perl's
usefulness stems from its extensibility - the facility with which it can
act as the high-level glue that holds together any number of low-level
components.

sherm--
 
J

Jussi Mononen

Actually it is not, "//" is a C++ single-line comment, but *most*
Actually it is. :) Single-line comments are included in the current C99
standard. They weren't part of the C89 standard, but as you say, most
compilers accepted them anyway.

:-D

I stand corrected, I think I must read the C99 specs again.
Indeed. It's also fairly easy to create Perl modules that wrap C
libraries.

Modules written in C are sometimes the only way to get Perl fast enough.
I've been there and done that and I bought the t-shirt ;-)

/jUSSi
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,708
Messages
2,569,347
Members
44,654
Latest member
7Jhamal74

Latest Threads

Top