Reading NIS using fsockopen in php

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Reading NIS using fsockopen in php

Arjen Korevaar
OS: Fedora Core 4
APCUPSD version: 3.10.18
UPS: APC SmartUPS 5000
PROBLEM:
 
I would like to create my own sort of upsstats.cgi, by using fsockopen and php. Now,
after reading the upsstats.c and upsfetch.c files, it seems to me that it's nothing more
than opening a socket to the NIS server at 3551, writing 'status' to it and retrieve
whatever you get back.
 
 
After that one is able to get the different variables, by using the list found at the top
of the upsfetch.c file.
 
However, I can open a socket using fsockopen to the NIS server. I can write the string
'status' to it (and get back int 6 indicating 6 bytes were written), but I can't seem to
retreive any information.
 
Below the php code I have used so far (very basic):
 
$nisserver = "172.16.10.1";
$nisport = 3351;
$fp = fsockopen($nisserver, $nisport, $errno, $errstr, 30);
if (!$fp) {
     echo "$errstr ($errno)<br />\n";
} else {
     $out = "status";
 
     echo fwrite($fp, $out);
     while (!feof($fp)) {
          echo fgets($fp, 256);
     }
     fclose($fp);
}
 
This should at least give me some (unformatted) reply right ?
 
Any help would be appreciated!
 
BTW1: The upsstat.cgi that came with apcupsd works perfectly, so the NIS server is ok.
BTW2: I've tried writing 'status\0' because this string terminator was used in upsstats.c
BTW3: I've used google ;)
BTW4: For those who read this and don't have the upsstats.c and upsfetch.c, I believe
the code below is the interesting part from upsfetch.c, loading UPS data from the NIS
server into memory (which is later used by the rest of the code to format and display the
various data):
 
static int fill_buffer(int sockfd)
{
     int n, stat = 1;
     char buf[1000];
 
     statbuf[0] = '\0';
     statlen = 0;
     if (net_send(sockfd, "status", 6) != 6) {
          net_errmsg = "fill_buffer: write error on socket\n";
          return 0;
     }
 
     while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) {
          buf[n] = '\0';
          strcat(statbuf, buf);
     }
     if (n < 0)
          stat = 0;
 
     statlen = strlen(statbuf);
     return stat;
}
 
Thanks a lot !

A. Korevaar
____________________________________

Website:   http://www.mephix.com
E-Mail:   [hidden email]
GSM:   +31 (0)6 543 245 63

 
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Reading NIS using fsockopen in php

Adam Kropelin
Arjen Korevaar wrote:

> OS: Fedora Core 4
> APCUPSD version: 3.10.18
> UPS: APC SmartUPS 5000
> PROBLEM:
>
> I would like to create my own sort of upsstats.cgi, by using
> fsockopen and php. Now,
> after reading the upsstats.c and upsfetch.c files, it seems to me
> that it's nothing more
> than opening a socket to the NIS server at 3551, writing 'status' to
> it and retrieve
> whatever you get back.

Close, but not quite. Look at net_send() in apclibnis.c. The actual wire
protocol includes a length word, sent as a 16 bit integer in network
byte order. This is also true of receive data as well; the stream
consists of length words followed by data.

--Adam



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
Apcupsd-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/apcupsd-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Reading NIS using fsockopen in php

Adam Kropelin
In reply to this post by Arjen Korevaar
When asking for help on a public list it's a good idea to keep the list
cc:ed so others can benefit from the discussion or make suggestions of
their own. It's easy to overlook because the mailing list defaults to
replying to the sender only. I've added apcupsd-users back to the cc:
list.

Arjen Korevaar wrote:
> Calculating the size of 'status' and sending it's size followed by
> 'status' Itself seems to be no problem.
>
> I have some difficulties with the socket_read function, as I can't
> seem to Calculate the 'size' of it (because I expect to receive data,
> rather than Send data).
>
> Further help would be muchly appreciated.

The protocol works the same in both directions. On the read side you
will first read a 16 bit integer in network byte order. That integer
tells you the number of bytes of data that follow. Repeat reading length
followed by data until you read a 0 length, which means the data stream
is completed.

--Adam



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
Apcupsd-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/apcupsd-users
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Reading NIS using fsockopen in php

Arjen Korevaar
In reply to this post by Arjen Korevaar
Thanks a lot ! Converting the length's to and from 16bit shorts solved it!

Working (tested) code :

<?
$host = "172.16.10.1";
$port = "3551";
$msg = "status";
$output = "";
$buf = "";

$socket = socket_create(AF_INET, SOCK_STREAM, 0);
if (socket_connect($socket, $host, $port) > 0) {
        // calculate length of message and pack it as a 16 bit short:
        $len = pack("n", strlen($msg));

        // write this length to the socket, followed by the actual message:
        socket_write($socket, $len, 2);
        socket_write($socket, $msg, strlen($msg));

        // receive the length of the reply as a 16 bit short:
        socket_recv($socket, $buf, 2, 0);
        // unpack this length back to an array containing one integer:
        $len = unpack("n", $buf);

        while ($len[1] > 0) {
                // read the current line and add this to the output, then
retrieve
                // the length of the next line. While the next line's length
is
                // larger then 0, proceed reading the next line.
                socket_recv($socket, $buf, $len[1], 0);
                $output .= $buf . "<br>";

                socket_recv($socket, $buf, 2, 0);
                $len = unpack("n", $buf);
        }
        // Length has reached zero, so we're done reading.
        socket_close($socket);
}
echo $output;
?>

Perhaps this may be usefull for somebody else!

A. Korevaar
________________________________
Website:   http://www.mephix.com 
E-Mail:    [hidden email]
GSM:       +31 (0)6 543 245 63

 
-----Oorspronkelijk bericht-----
Van: Adam Kropelin [mailto:[hidden email]]
Verzonden: zondag 11 september 2005 16:09
Aan: Arjen Korevaar
CC: [hidden email]
Onderwerp: Re: [Apcupsd-users] Reading NIS using fsockopen in php

On Sun, Sep 11, 2005 at 02:32:16PM +0200, Arjen Korevaar wrote:

> Thank you for your help so far. I guessed it wouldn't be difficult to
> rewrite some of the c code to php, as these languages have basically
> the same origin and look a lot like eachother.
>
> I don't know if you're familiar with the php programming language, but
> I'd like you to take a look at my code-so-far one more time...
>
> <?
> $host = "172.16.10.1";
> $port = "3551";
> $msg = "status";
> $buf = "test"; // just to see if it has changed after reading
>
> $socket = socket_create(AF_INET, SOCK_STREAM, 0); if
> (socket_connect($socket, $host, $port) > 0) {
> socket_write($socket, strlen($msg) . "\0", strlen(strlen($msg)));
                              ^^^^^^^^^^^^^^^^^^^ That bit doesn't make
sense. You're taking a length (an integer) and appending an ASCII NUL onto
it. I assume what you're trying to do is send the 16 bit length. First, you
need to send it as raw binary, not ASCII. Second, it needs to be exactly 16
bits (two bytes); your code is not ensuring that.

You want something like this:

        $len = pack("n", strlen($msg));
        socket_write($socket, $len, 2);

> socket_write($socket, $msg . "\0", strlen($msg));

Get rid of the "\0", otherwise that code is correct.

> socket_recv($socket, $buf, 1024, 0);

Now you want to first read a 16 bit length:

        socket_recv($socket, $buf, 2, 0);
        $len = unpack("nlen", $buf)["len"];

Now read the number chars specified by the length:

        socket_recv($socket, $buf, $len);

Note this code isn't actually tested, but you should get the idea. Look up
the definitions of pack() and unpack() in the php docs to see how they work.

--Adam





-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
Apcupsd-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/apcupsd-users
Loading...