Monday, May 15, 2000
More MONitoring of the NETwork
So I'm still working on monnet.
I basically started over from
scratch, reworking the code although the basic structure is the same from
the old version. The output from the program looks like:
0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.72.81 TCP 25945 80 A 00C07B4D7D81 0040332E103C IPv4 205.229.72.81 208.26.72.3 TCP 80 25945 AP 00C07B4D7D81 0040332E103C IPv4 205.229.72.81 208.26.72.3 TCP 80 25945 AP F 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.72.81 TCP 25945 80 A 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.74.191 TCP 25944 80 A F 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.74.190 TCP 25950 80 S 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.72.81 TCP 25945 80 A F 00C07B4D7D81 0040332E103C IPv4 205.229.74.218 208.26.72.3 TCP 80 25944 R 00C07B4D7D81 0040332E103C IPv4 205.229.74.190 208.26.72.3 TCP 80 25950 A S 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.74.190 TCP 25950 80 A 00C07B4D7D81 0040332E103C IPv4 205.229.72.81 208.26.72.3 TCP 80 25945 A 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.74.190 TCP 25950 80 AP 00C07B4D7D81 0040332E103C IPv4 205.229.74.190 208.26.72.3 TCP 80 25950 A 00C07B4D7D81 0040332E103C IPv4 205.229.74.190 208.26.72.3 TCP 80 25950 AP 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.74.190 TCP 25950 80 A 00C07B4D7D81 0040332E103C IPv4 205.229.74.190 208.26.72.3 TCP 80 25950 AP 00C07B4D7D81 0040332E103C IPv4 205.229.74.190 208.26.72.3 TCP 80 25950 A F 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.74.190 TCP 25950 80 A 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.74.190 TCP 25950 80 A F 00C07B4D7D81 0040332E103C IPv4 205.229.74.190 208.26.72.3 TCP 80 25950 A 0040332E103C 00C07B4D7D81 IPv4 208.26.72.3 205.229.74.190 TCP 26000 80 S 02608CD87517 00C07B4D7D81 ARP A:request ETH:IPv4 208.26.72.2 208.26.72.1 00C07B4D7D81 02608CD87517 ARP A:reply ETH:IPv4 208.26.72.1 208.26.72.2 0040332E103C 00C07B4D7D81 ARP A:request ETH:IPv4 208.26.72.3 208.26.72.1 00C07B4D7D81 0040332E103C ARP A:reply ETH:IPv4 208.26.72.1 208.26.72.3 00C07B4D7D81 0040332E103C IPv4 208.26.72.1 208.26.72.3 ICMP redirect host 208.26.72.4
And the report it can generate:
Total: 64,813 13.45M IPv4 64,017 12.55M ICMP 245 16.34K echo reply 18 1.23K error 147 10.15K host unreachable 4 436 port unreachable 142 9.68K comm prohibited by filters 1 46 redirect 8 368 host 8 368 echo request 18 1.21K TTL 54 2.43K > 0 during transit 54 2.43K TCP 58,998 11.66M UDP 4,774 516.03K ARP 796 33.38K A:request 425 17.35K A:reply 371 16.03K
Generating that report while the program is running was tricky. I didn't
want to loose any packets so creating a thread or process (I am doing this
under Unix) to handle that should minimize the number of packets lost. I'll
skip threads since personally I don't like the way pthreads
works
(I think the API sucks but that's me and I really can't quantify it more
than that) and that leaves fork()
(at least under Unix).
But I don't feel that good about the code, since I'm now dealing with signals, and the semantics of signals under Unix is … well … it sucks. I'm sure I have race conditions in there.
Stripping strips from a website
I started reading a new on-line strip, Player Versus Player. Seems promising but I'd like to read the archive, of which it reaches back to May of 1998, making it two full years of archives to go through.
It's a simple enough matter to write a program that downloads the entire archive of strips:
while(1) { sprintf(filename,"%d%02d%02d.gif",year,month,day); sprintf(url,"http://www.pvponline.com/archive/%d/pvp%s",year,filename); sprintf(cmd,"lynx -source %s >%s",url,filename); system(cmd); sleep(10); /* be nice on their server */ day ++; if (day > daysinmonth(year,month)) { day = 1; month++; if (month > 12) { month = 1; year ++; if (isthistoday(year,month,day)) break; } } }
I feel somewhat odd about doing that though, seeing how they get their revenue through advertising (not that I agree that's the best way to make money, but that's beside the point). Well, that and if they check their logs and see a bunch of requests for just the strips, every 10 seconds, well, in case I do end up liking the strip I don't want to be banned from their server.
Elapsed time is …
Okay, in monnet
I'm keeping track of how long the program runs so
when the report is printed, you can see how much time has elapsed since the
program started. I want the display to look something like:
10d 14h 13m 33s
. Make it easier to read than something like
915213s
.
Under ANSI C,
you have the various functions under time.h
and the “official” way to calculate elapsed time is to call
difftime()
(as you portably can't assume that time_t
is in
sections, or even a integral type). That returns, as a double, the number
of seconds between the two time values.
The problem is, you can't really take that result, stick it into a
struct tm
and call mktime()
to renormalize it, as the
value could overflow an int
(which is what each field is defined as
in struct tm
). An int
is defined as a minimum of 16 bits,
which isn't even enough to record the number of seconds in a day. Sure, on
modern systems int
s are probably 32 bits in size, but that only
leaves you some 68 years before the seconds overflow (it should be fun in
2038).
So it's more portable to do the math directly.
So, I thought I'd be cute and try to do the minimal amount of math possible,
and in looking over math.h
I saw modf()
, which splits a
double into its integral portion and fractional portion. So, I tried:
diff = difftime(end,start); diff /= 60.0; tmp = modf(diff,&diff); sec = tmp * 60.0; diff /= 60.0; tmp = modf(diff,&diff); min = tmp * 60.0; diff /= 24.0; tmp = modf(diff,&diff); hour = tmp * 24.0; diff /= 365.0; tmp = modf(diff,&diff); day = tmp * 365.0; year = diff;
only to have it fail miserably. Even several variations on that didn't work. So I bit the bullet and did it the old fasion way:
#define SECSMIN (60.0) #define SECSHOUR (60.0 * 60.0) #define SECSDAY (60.0 * 60.0 * 24.0) #define SECSYEAR (60.0 * 60.0 * 24.0 * 365.2422) diff = difftime(end,start); year = (int)(diff / SECSYEAR); diff -= ((double)year) * SECSYEAR; day = (int)(diff / SECSDAY); diff -= ((double)day) * SECSDAY; hour = (int)(diff / SECSHOUR); diff -= ((double)hour) * SECSHOUR; min = (int)(diff / SECSMIN); diff -= ((double)min) * SECSMIN; sec = (int)(diff);