Today's Page Hits: 560
I have more hair and it isn't so grey. :->
This page validates as XHTML 1.0, and will look much better in a browser that supports web standards, but it is accessible to any browser or Internet device. It was created using techniques detailed at glish.com/css/.
So mountd maps network addresses into unsigned integers. I want to map them back. My first pass at it fails:
% cat a.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
int
main (int argc, char *argv[])
{
char *p = argv[1];
uint_t addr = 0;
uint_t rev;
int i;
char sep = ' ';
for (i = 0; i < 4; i++) {
addr |= atoi(p) << ((3-i) * 8);
p = strchr(p, '.');
if (p == NULL)
break;
p++;
}
printf("%s yields %u and that reverse maps to ", argv[1], addr);
for (i = 0; i < 4; i++) {
rev = addr >> ((3-i) * 8);
printf("%c%u", sep, rev);
sep = '.';
}
printf("\n");
return (0);
}
% ./a.out 192.168.1.2
192.168.1.2 yields 3232235778 and that reverse maps to 192.49320.12625921.3232235776
We see the idea works in that it gets the first octet correct. If we were to mask each octet again, it would probably also work.
The next simple approach also fails:
printf("%u.%u.%u.%u\n", addr & 0xff000000, addr & 0x00ff0000,
addr & 0x0000ff00, addr & 0x000000ff);
as this shows
./a.out 192.168.1.256 192.168.1.256 yields 3232235776 and that reverse maps to 3221225472.11010048.256.0
This gets us the right number, but it keeps it too far out. We need to get the right number and then shift it back down. (Note my earlier comment about remasking in the first approach):
for (i = 0; i < 4; i++) {
shift = ((3-i) * 8);
rev = (addr & (0xff << shift)) >> shift;
printf("%c%u", sep, rev);
sep = '.';
}
We are close, oh so close:
./a.out 192.168.1.256 192.168.1.256 yields 3232235776 and that reverse maps to 192.168.1.0
Perhaps we are really there, look at the ip I gave, it is invalid. :-> What does valid input yield?
% ./a.out 192.168.1.255 192.168.1.255 yields 3232236031 and that reverse maps to 192.168.1.255 % ./a.out 192.168.1.2 192.168.1.2 yields 3232235778 and that reverse maps to 192.168.1.2 % ./a.out 192.168.1.3 192.168.1.3 yields 3232235779 and that reverse maps to 192.168.1.3 % ./a.out 192.168.1.4 192.168.1.4 yields 3232235780 and that reverse maps to 192.168.1.4 % ./a.out 192.168.1.0 192.168.1.0 yields 3232235776 and that reverse maps to 192.168.1.0
So, even when prototyping, you should be doing some validity checking. I might have spent a chunk of time trying to fix code that was really working. I grabbed that test case from my command line history. It was the first that looked correct. We can add some simple checking in the first loop:
for (i = 0; i < 4; i++) {
t = strtol(p, &junk, 10) << ((3-i) * 8);
if (junk && junk[0] != '.') {
fprintf(stderr, "%s is wrong in the %d octet,"
" %s has non-digits as %s\n", argv[1],
4-i, p, junk);
exit (-1);
} else if (rev > 255 || t < 0) {
fprintf(stderr, "%s is wrong in the %d octet,"
" %d is out of range\n", argv[1],
4-i, t);
exit (-1);
}
addr |= t;
Which yields this incorrect result:
% ./a.out 192.168.1.1 192.168.1.1 is wrong in the 1 octet, -1073741824 is out of range
Took me a while to realize I was shifting too early. This fix:
t = strtol(p, &junk, 10);
if (junk && junk[0] != '.' && junk[0] != '\0') {
...
addr |= t << ((3-i) * 8);
works:
% ./a.out 192.168.1.1 192.168.1.1 yields 3232235777 and that reverse maps to 192.168.1.1 % ./a.out 192.168.1aa.1 192.168.1aa.1 is wrong in the 3 octet, 1aa.1 has non-digits as |aa.1| % ./a.out 192.168.1.256 192.168.1.256 is wrong in the 4 octet, 256 is out of range
Note that I had to change the junk check because strtol(3C) will return a pointer to the EOS. Which I had never hit before in coding - it seems counterintuitive.
In editing this, I noticed that the first approach was actually very close to being correct and a simple change would have sufficed:
for (i = 0; i < 4; i++) {
rev = (addr >> ((3-i) * 8)) & 0xff;
printf("%c%u", sep, rev);
sep = '.';
}
This change makes use of the fact we know exactly which bits we want to mask off. It removes another shifting operation and would be preferred over the other final solution.
So I now have the ability to store the attribute-expressions as parse trees and convert those back to human readable rules. This will allow me to not store the string representation. As a bonus, I've also got most of the network error checking ready to add to the prototype.